diff --git a/docs/.vuepress/public/img/2000000033.jpg b/docs/.vuepress/public/img/2000000033.jpg new file mode 100644 index 0000000..b0d8c85 Binary files /dev/null and b/docs/.vuepress/public/img/2000000033.jpg differ diff --git a/docs/.vuepress/public/img/2000000034.png b/docs/.vuepress/public/img/2000000034.png new file mode 100644 index 0000000..2346342 Binary files /dev/null and b/docs/.vuepress/public/img/2000000034.png differ diff --git a/docs/.vuepress/public/img/2000000035.png b/docs/.vuepress/public/img/2000000035.png new file mode 100644 index 0000000..f4d0e97 Binary files /dev/null and b/docs/.vuepress/public/img/2000000035.png differ diff --git a/docs/.vuepress/public/img/2000000036.png b/docs/.vuepress/public/img/2000000036.png new file mode 100644 index 0000000..3cc1e6c Binary files /dev/null and b/docs/.vuepress/public/img/2000000036.png differ diff --git a/docs/.vuepress/public/img/2000000037.png b/docs/.vuepress/public/img/2000000037.png new file mode 100644 index 0000000..8572e51 Binary files /dev/null and b/docs/.vuepress/public/img/2000000037.png differ diff --git a/docs/.vuepress/public/img/2000000038.png b/docs/.vuepress/public/img/2000000038.png new file mode 100644 index 0000000..c3b9b44 Binary files /dev/null and b/docs/.vuepress/public/img/2000000038.png differ diff --git a/docs/.vuepress/public/img/2000000039.png b/docs/.vuepress/public/img/2000000039.png new file mode 100644 index 0000000..5056460 Binary files /dev/null and b/docs/.vuepress/public/img/2000000039.png differ diff --git a/docs/Changelog/readme.md b/docs/Changelog/readme.md index f517ed6..d0829ec 100644 --- a/docs/Changelog/readme.md +++ b/docs/Changelog/readme.md @@ -5,6 +5,23 @@ title: 更新日志 --- +## 2024.6.9 + +

+ +
+ + + + ## 2024.5.6

diff --git a/docs/CloudService/S3/limiting-bucket-upload-types-using-cloud-functions.md b/docs/CloudService/S3/limiting-bucket-upload-types-using-cloud-functions.md new file mode 100644 index 0000000..7a11a80 --- /dev/null +++ b/docs/CloudService/S3/limiting-bucket-upload-types-using-cloud-functions.md @@ -0,0 +1,183 @@ +--- +title: 使用云函数限制存储桶上传类型 + +--- + +

使用云函数限制存储桶上传类型

+ +--- + +## 前言 + +相信不少师傅都挖到过存储桶任意文件上传的漏洞,不过由于存储桶的特性,这种任意文件上传的危害性相对传统站点要低一些,但仍然具备一定的风险,比如可以被拿来当做钓鱼或者挂黑页等等。 + +常规修复这类风险的办法是通过在后端代码里限制文件的上传类型,网上已经有了相应的文章,本文将探讨另外一个方法,即使用云函数去限制存储桶的文件上传类型。 + +本文将以限制存储桶只能上传图片的场景为例,至于怎么限制其他类型则只需要对函数代码稍加修改就能实现,为了更好的理解本文内容,这里简单绘制了一个流程图如下。 + +
+ +## 操作步骤 + +这里以阿里云为例,首先在函数计算 FC 服务里创建一个事件函数,这里函数的区域需要和目标存储桶的区域保持一致。 + +
+ +运行环境选择 Python,然后将下面的代码保存为 index.py 文件后压缩成 ZIP 包,再将 ZIP 包上传到云函数中。 + +```python +import os +import json +import oss2 +import imghdr + + +def handler(event, context): + # 获取临时访问凭证并进行认证 + creds = context.credentials + auth = oss2.StsAuth(creds.access_key_id, creds.access_key_secret, creds.security_token) + + # 获取上传文件的相关信息 + evt_lst = json.loads(event) + evt = evt_lst['events'][0] + bucket_name = evt['oss']['bucket']['name'] + object_key = evt['oss']['object']['key'] + endpoint = 'oss-' + evt['region'] + '-internal.aliyuncs.com' + bucket = oss2.Bucket(auth, endpoint, bucket_name) + + # 获取上传文件的后缀类型 + upload_file_suffix_type = os.path.splitext(object_key)[1].replace('.', '') + + # 获取上传文件的内容类型 + head_result = bucket.head_object(object_key) + upload_file_content_type = head_result.headers.get('Content-Type') + + # 获取上传文件的文件头类型 + upload_file_content = bucket.get_object(object_key).read() + upload_file_header_type = imghdr.what(None, h=upload_file_content[:32]) + + print(f'[+] 文件上传路径:oss://{bucket_name}/{object_key}') + print(f'[+] 文件头类型:{upload_file_header_type}') + print(f'[+] 文件后缀类型:{upload_file_suffix_type}') + print(f'[+] 文件 Content-Type:{upload_file_content_type}') + + # 允许上传的文件类型列表 + allowed_types = ['jpg', 'jpeg', 'png', 'gif'] + allowed_content_types = ['image/jpeg', 'image/png', 'image/gif'] + + # 检查文件类型是否合规 + Compliant = 0 + print('[+] 正在检查上传的文件是否合规 ……') + if upload_file_header_type not in allowed_types: + print('[-] 文件头类型检查不通过。') + else: + print('[+] 文件头类型检查通过。') + if upload_file_suffix_type not in allowed_types: + print('[-] 文件后缀类型检查不通过。') + else: + print('[+] 文件后缀类型检查通过。') + if upload_file_content_type not in allowed_content_types: + print('[-] 文件 Content Type 检查不通过。') + else: + print('[+] 文件 Content Type 检查通过。') + Compliant = 1 + + # 删除不允许上传的文件 + if Compliant: + print(f'[+] 文件 oss://{bucket_name}/{object_key} 检查通过。') + else: + print(f'[-] 文件 oss://{bucket_name}/{object_key} 检查不通过,正在删除该文件。') + bucket.delete_object(object_key) + print(f'[!] 文件 oss://{bucket_name}/{object_key} 已被删除。') +``` + +由于我们在这里的 Python 代码中需要调用到 GetObject 和 DeleteObject 的 API,因此还需要为这个函数配置一个至少具备这两个操作权限的角色。 + +这里我们在 IAM 里创建一个角色,这个角色的最低权限要求如下: + +```json +{ + "Version": "1", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "oss:GetObject", + "oss:DeleteObject" + ], + "Resource": "acs:oss:oss-::/*" + } + ] +} +``` + +信任策略如下: + +```json +{ + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": [ + "fc.aliyuncs.com" + ] + } + } + ], + "Version": "1" +} +``` + +角色创建完成后,在「高级配置」这里选择我们在函数中要使用的角色名称,其他地方可以保持默认或者根据自己的需求进行修改,最后点击函数「创建」按钮。 + +
+ +创建完云函数后,我们还需要为这个函数创建一个触发器,从而让存储桶有文件上传时能够触发这个函数的执行。 + +在函数配置页面中,选择「触发器」,点击「创建触发器」,触发类型选择 OSS,Bucket 名称选择自己需要限制文件上传类型的 Bucket,触发事件这里选择 PutObject,角色直接使用默认角色,最后点击「确定」,这样所有的配置就完成了。 + +
+ +此时我们向存储桶上传一个正常的文件,可以看到三项检查都是通过的,这样文件是能正常上传的。 + +
+ +如果上传一个后缀是 html 的文件,那么检查就是不通过的,此时云函数就会把这个文件从存储桶中删掉。 + +
+ +如果上传的文件名是 png 后缀的,Content-Type 是 image/jpeg,但 Body 部分不是图片类型同样也会无法上传。 + +
+ +到此为止,已经能够基本实现使用云函数去限制文件上传类型了,不过这里还有一些可以优化的地方以及一些局限性留给读者探讨。 + +**可以优化的地方:** + +1. 如果想识别其他类型的文件,例如 zip、txt 等格式,这里使用的 imghdr 库就不够用了,imghdr 只能识别出图片文件的类型,这时可以使用第三方库,例如 python-magic 库。 +2. 这里代码中采取的策略是检测到不合规的文件会直接执行删除操作,在实际场景中直接删除可能具有一定的风险性,尤其是存在存储桶同名称覆盖问题的时候,因此这里还是需要根据自身业务情况做适当的调整。 + +**存在局限性的地方:** + +由于云函数里的 OSS 触发器只能采取异步的方式执行,因此云函数在触发时,文件就已经被上传到存储桶里了,所以没办法解决在上传同名称文件时被覆盖的问题,这个问题目前似乎只能通过后端代码去解决。 + +## 总结 + +本文为限制存储桶文件上传类型提供了一个新的解决方案,但也具备一定的局限性。 + +此外在当前存储桶策略里我注意到在资源路径下可以使用 *.png 来限制文件的上传后缀,不过目前还没办法限制 Content Type,在此也希望云厂商能够在存储桶策略里加上限制 Content Type 的策略,这样限制存储桶的文件上传类型就更方便了,提升存储桶的安全性也会变得更加简单。 + +不过如果想要有更严格的限制策略,那么还是云函数或者后端代码具有更高的自由度。 + + + + + \ No newline at end of file diff --git a/docs/CloudService/sidebar_contents.js b/docs/CloudService/sidebar_contents.js index 4a351e8..99cba3a 100644 --- a/docs/CloudService/sidebar_contents.js +++ b/docs/CloudService/sidebar_contents.js @@ -13,6 +13,7 @@ module.exports = [ "/CloudService/S3/bucket-policy-able-to-write", "/CloudService/S3/bucket-object-traversal", "/CloudService/S3/specific-bucket-policy-configuration", + "/CloudService/S3/limiting-bucket-upload-types-using-cloud-functions" ] }, {