阿里云OSS防盗链与权限访问控制完全指南
引言:为什么需要重视OSS的访问控制
对象存储服务(OSS)作为阿里云最核心的存储产品之一,承载着海量企业的图片、视频、文档等静态资源。然而,随着业务规模的扩大,资源被盗链、数据被未授权访问、流量费用激增等问题频发。如何科学地配置防盗链与权限访问控制,成为每个OSS使用者必须掌握的技能。
OSS提供了多层次、多维度的安全防护体系:从基础的Referer防盗链,到精细化的Bucket Policy和RAM Policy权限策略,再到临时授权的签名URL与STS机制。本文将从原理到实践,逐一剖析这些技术手段,帮助读者构建一套完整、安全的OSS访问控制方案。
需要先登录阿里云控制台,点击:阿里云控制台
一、防盗链:基于Referer的第一道防线
1.1 什么是防盗链
防盗链是OSS提供的一种基于HTTP请求头中Referer字段的访问控制机制。当用户通过浏览器或应用访问OSS资源时,请求头中会携带来源页面的URL(即Referer)。OSS通过检查这个Referer是否在允许的白名单中,来决定是否放行该请求。这一机制的核心价值在于:防止其他网站将您的OSS资源嵌入自己的页面,从而盗用带宽和流量,给您带来不必要的费用支出。
1.2 防盗链的三种配置要素
在OSS控制台配置防盗链时,需要关注三个核心参数:
白名单Referer:允许访问的域名列表。只有来自这些域名的请求才会被放行。多个Referer之间使用回车换行分隔。配置时需要注意,白名单中的域名需要同时包含http和https两种协议版本。
黑名单Referer:禁止访问的域名列表。黑名单中的域名发起的请求将被直接拒绝。当白名单和黑名单同时存在时,OSS会先判断黑名单,再判断白名单。这一顺序意味着:即使某个域名同时出现在白名单和黑名单中,它也会被黑名单规则拦截。
空Referer策略:决定是否允许请求头中不带Referer或Referer为空的请求。如果选择"不允许",则所有浏览器中直接输入URL访问OSS文件的行为都会被拒绝。这在某些场景下可能影响正常使用——例如用户从浏览器地址栏直接访问图片、或者某些隐私浏览器不发送Referer时。
1.3 防盗链的生效逻辑
防盗链的判定逻辑可以总结为以下三种情况:
第一种情况:如果Referer白名单为空,则所有请求都会被允许,防盗链功能实际上处于未启用状态。
第二种情况:如果Referer白名单不为空,且不允许空Referer,则只有Referer属于白名单的请求被允许,其他请求(包括Referer为空的请求)都会被拒绝。
第三种情况:如果Referer白名单不为空,但允许空Referer,则Referer为空的请求和符合白名单的请求会被允许,其他请求都会被拒绝。
理解这一逻辑至关重要。很多用户在配置防盗链后发现自己的网站无法访问OSS资源,往往是因为没有正确设置空Referer策略——例如,当用户从HTTPS页面引用HTTP资源时,某些浏览器可能不会发送Referer,此时如果防盗链设置为"不允许空Referer",请求就会被拒绝。
1.4 QueryString截断规则
在防盗链配置中,还有一个容易被忽视的选项——截断QueryString。当选择"允许"截断时,OSS在匹配Referer时会忽略URL中的查询参数。例如,将Referer设置为 http://www.example.com/?action=nop,OSS实际会使用 http://www.example.com/ 进行匹配。选择"不允许"时,则会完整匹配带查询参数的URL。这一配置对于使用了动态参数的网站尤为重要,需要根据实际业务场景选择合适的策略。
1.5 通过Java SDK配置防盗链
除了控制台图形化操作,OSS也支持通过SDK编程方式配置防盗链。以下是一个使用Java SDK设置防盗链的完整示例:
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.BucketReferer;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import java.util.ArrayList;
import java.util.List;
public class RefererDemo {
public static void main(String[] args) throws Exception {
// 从环境变量获取访问凭证
EnvironmentVariableCredentialsProvider credentialsProvider =
CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Endpoint和Bucket名称
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
String bucketName = "examplebucket";
// 创建OSSClient实例
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
try {
// 构建Referer白名单
List<String> refererList = new ArrayList<String>();
refererList.add("https://www.example.com");
refererList.add("http://www.example.com");
// 创建BucketReferer对象
// 参数说明:白名单列表,是否允许空Referer,是否截断QueryString
BucketReferer bucketReferer = new BucketReferer(refererList, false, true);
// 设置防盗链配置
ossClient.setBucketReferer(bucketName, bucketReferer);
System.out.println("防盗链配置成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭OSSClient
ossClient.shutdown();
}
}
}需要注意的是,设置防盗链需要具备 oss:PutBucketReferer 权限。在实际生产环境中,建议通过RAM用户而非主账号进行操作,以遵循最小权限原则。
1.6 通过ossutil命令行配置防盗链
对于运维自动化场景,ossutil命令行工具提供了更高效的配置方式。查看当前防盗链配置:
ossutil api get-bucket-referer --bucket examplebucket以JSON格式查看:
ossutil api get-bucket-referer --bucket examplebucket --output-format json设置防盗链则通过 put-bucket-referer 命令完成,需要将配置写入JSON文件后通过 --body 参数传入。
二、权限访问控制:多层次防护体系
防盗链只能解决"谁可以引用"的问题,但无法控制"谁可以读取、写入、删除"。OSS提供了四层权限控制机制,从简单到复杂依次是:ACL、Bucket Policy、RAM Policy,以及临时授权机制(签名URL和STS)。
2.1 ACL:最基础的权限控制
ACL(访问控制列表)是OSS中最简单、最直接的权限控制方式。它通过预定义的权限等级来控制资源的公开或私有状态,支持以下三种等级:
私有(private):数据完全私有,仅资源拥有者或被授权的用户可访问。这是Bucket的默认配置,也是推荐的安全配置。
公共读(public-read):任何人都可以读取数据,但只有资源拥有者或被授权用户可以写入。适用于需要对外提供公开静态资源的场景,如图片、CSS、JavaScript文件等。
公共读写(public-read-write):任何人都可以公开读取和写入数据。这种权限等级风险极高,除非有特殊需求,否则强烈不建议使用。
Bucket ACL控制整个存储空间的默认访问权限,而Object ACL可以单独控制某个对象的权限,且优先级高于Bucket ACL。也就是说,即使Bucket设置为私有,也可以为某个特定文件设置公共读权限。
2.2 Bucket Policy:基于资源的精细化授权
当ACL无法满足复杂的授权需求时,Bucket Policy提供了更强大的能力。Bucket Policy是直接附加在Bucket上的授权策略,可以定义谁(Principal)在什么条件下(Condition)可以对哪些资源(Resource)执行什么操作(Action)。
Bucket Policy的核心优势在于:
- 单条策略即可授权多个用户访问同一个Bucket,无需为每个用户单独配置
- 支持基于IP地址、VPC网络、访问时间等条件的精细化控制
- 支持授权给其他阿里云账号的RAM用户
- 支持授权给匿名用户(需谨慎使用)
- 配置简单,在控制台即可完成图形化操作
常见Bucket Policy配置示例
示例一:允许特定IP地址的匿名用户读取Bucket中的所有对象
{
"Statement": [
{
"Action": [
"oss:GetObject",
"oss:GetObjectAcl",
"oss:ListObjects"
],
"Condition": {
"IpAddress": {
"acs:SourceIp": [ "10.10.10.10" ]
}
},
"Effect": "Allow",
"Principal": [ "*" ],
"Resource": [
"acs:oss:*:174649585760xxxx:examplebucket/*"
]
}
],
"Version": "1"
}示例二:授予特定RAM用户对指定目录的只读访问权限
{
"Statement": [
{
"Action": [ "oss:GetObject" ],
"Effect": "Allow",
"Principal": [ "acs:ram::1234567890:user/username" ],
"Resource": [
"acs:oss:*:1234567890:examplebucket/hangzhou/2020/*",
"acs:oss:*:1234567890:examplebucket/hangzhou/2015/*"
]
}
],
"Version": "1"
}配置Bucket Policy的重要注意事项
当Principal设置为通配符(*)且不包含Condition时,策略仅对Bucket Owner以外的用户生效。当Principal设置为通配符(*)且包含Condition时,策略对所有用户生效——包括Bucket Owner和匿名用户。这意味着,如果配置了拒绝访问的Condition策略,连Bucket Owner自身也会被拒绝访问,可能导致整个Bucket无法访问。因此,配置Bucket Policy时务必谨慎。
另外,acs:SourceIp条件关键字仅匹配请求的源IP地址,不区分该IP来自公网还是VPC内网。如果仅使用acs:SourceIp限制访问,其他VPC中恰好使用相同IP地址段的请求也可能被放行,存在越权访问风险。最佳实践是同时配置acs:SourceVpc来明确请求的网络来源。
2.3 RAM Policy:基于身份的权限管理
RAM Policy是附加在RAM用户、用户组或RAM角色上的授权策略。与Bucket Policy不同,RAM Policy是"基于身份"的——它定义的是"这个用户能做什么",而非"这个Bucket允许谁访问"。
OSS支持两种RAM Policy类型:
系统策略:由阿里云预置,用户只能使用不能修改。最常用的两个系统策略是 AliyunOSSFullAccess(OSS完全管理权限)和 AliyunOSSReadOnlyAccess(OSS只读权限)。
自定义策略:由用户自行创建和维护,提供最灵活的权限配置能力。自定义策略采用JSON格式编写,核心元素包括:
- Effect:授权效力,取值为 Allow(允许)或 Deny(拒绝)
- Action:对资源执行的具体操作,支持使用通配符 *
- Resource:策略作用的资源范围
- Condition:策略生效的条件(可选)
自定义RAM Policy示例
以下策略允许对 example-bucket 及该Bucket内所有资源执行全部操作:
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": "oss:*",
"Resource": [
"acs:oss:*:*:example-bucket",
"acs:oss:*:*:example-bucket/*"
]
}
]
}RAM Policy与Bucket Policy的协同工作
当RAM Policy和Bucket Policy同时存在时,OSS会综合评估所有策略。权限判定的核心原则是:
- 显式拒绝优先:任何策略中存在匹配请求的Deny规则,请求立即被拒绝
- 寻找显式允许:不存在Deny规则时,若存在匹配的Allow规则,请求被允许
- 默认拒绝:既无Deny也无Allow,请求默认被拒绝
这一原则意味着:即使某个RAM Policy允许了某操作,如果某个Bucket Policy明确拒绝了该操作,请求依然会被拒绝。反之亦然。
2.4 OSS扁平化存储结构对权限配置的影响
OSS采用扁平化存储模型,所有文件直接隶属于存储空间,物理上不存在目录层级结构。控制台中看到的"目录"实际上是通过对象Key的前缀和分隔符(/)模拟出来的。目录对象的Key以 / 结尾,这是OSS识别"目录"的标志。
这一结构对权限配置有重要影响:当需要授权访问某个"目录"时,实际上是在授权访问具有特定前缀的所有对象。例如,授权访问 Development/ 目录,等同于授权访问所有Key以 Development/ 开头的对象。
不同操作目标对应的API请求和Resource配置也不同:
- 列举存储空间根目录:调用 ListObjects(prefix为空,delimiter为/),Resource指向Bucket本身
- 进入某个文件夹:调用 ListObjects(prefix为文件夹名/,delimiter为/),Resource指向Bucket本身,通过Condition的oss:Prefix限制可列举范围
- 读写文件内容:Resource可精确到路径,如 acs:oss:*:*:examplebucket/文件夹名/*,支持通配符
通过OSS控制台访问时,用户需要从Bucket列表逐层导航进入目标目录,这比直接使用API/SDK需要更多的权限——除了目标资源的操作权限外,还需要 oss:ListBuckets、oss:GetBucketInfo 等辅助权限。
三、临时授权:签名URL与STS
在实际业务中,我们常常需要让没有OSS账号的第三方临时访问某个文件——比如让用户下载私有文件、让合作方上传数据等。此时,ACL、Bucket Policy、RAM Policy都无法满足需求,因为它们都需要预先定义好"谁"可以访问。签名URL和STS临时凭证正是为解决这一场景而生。
3.1 签名URL:为单个文件生成临时访问链接
签名URL(又称预签名URL)将签名信息和认证参数直接嵌入URL中,让您无需共享访问凭证即可授予对OSS资源的临时访问权限。任何持有该URL的人都可以在有效期内执行指定的操作(如下载、上传),URL过期后自动失效。
签名URL的核心特性
- 有效期可配置:使用V4签名算法时,AccessKey签名URL有效期最长为7天(604800秒),STS临时凭证签名URL最长为12小时(43200秒)
- 支持多次访问:在有效期内,同一个URL可以被多次使用
- 操作绑定:生成URL时指定HTTP方法(GET用于下载,PUT用于上传等),URL只能执行该操作
- 无需凭证:访问者无需持有任何AccessKey,直接使用URL即可
使用Python SDK生成签名URL(下载)
以下示例使用OSS Python SDK V2生成一个用于下载文件的预签名URL:
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
from datetime import timedelta
# 从环境变量加载凭证
credentials_provider = EnvironmentVariableCredentialsProvider()
# 配置Endpoint和Region
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
region = "cn-hangzhou"
bucket_name = "examplebucket"
object_name = "exampledir/exampleobject.pdf"
# 创建Bucket对象
auth = oss2.ProviderAuthV4(credentials_provider)
bucket = oss2.Bucket(auth, endpoint, bucket_name, region=region)
# 生成预签名URL,有效期30分钟
expires = timedelta(minutes=30)
result = bucket.presign('GET', object_name, expires=expires)
print("预签名URL:", result.url)
print("过期时间:", result.expiration)使用Python SDK生成签名URL(上传)
以下示例生成一个用于上传文件的预签名URL:
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 从环境变量加载凭证
credentials_provider = EnvironmentVariableCredentialsProvider()
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
region = "cn-hangzhou"
bucket_name = "examplebucket"
object_name = "exampledir/exampleobject.txt"
# 创建Bucket对象
auth = oss2.ProviderAuthV4(credentials_provider)
bucket = oss2.Bucket(auth, endpoint, bucket_name, region=region)
# 生成用于PUT上传的预签名URL,有效期60秒
# slash_safe=True确保路径中的斜杠不会被转义
url = bucket.sign_url('PUT', object_name, 60, slash_safe=True)
print("上传预签名URL:", url)上传者获得该URL后,只需发送HTTP PUT请求到该URL即可完成上传,无需任何OSS凭证。
签名URL的V4签名结构
一个完整的V4签名URL包含以下查询参数:
https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject
?x-oss-additional-headers=host
&x-oss-credential=LTAI********************/20241203/cn-hangzhou/oss/aliyun_v4_request
&x-oss-date=20241203T034420Z
&x-oss-expires=86400
&x-oss-signature=70c542eaf652ac291c0c343d63ac24ede41c0526661d9d4c63c0906a2686160c
&x-oss-signature-version=OSS4-HMAC-SHA256其中 x-oss-credential 包含AccessKeyId、日期、Region和服务名称。需要注意的是,URL中的斜杠需要进行URI编码。
3.2 STS临时凭证:为复杂场景提供临时身份
签名URL适用于单个文件的临时访问,但当需要为第三方应用提供持续的、多操作的OSS访问能力时,STS(Security Token Service)临时凭证是更好的选择。
STS的核心价值在于:
- 无需泄露长期AccessKey给第三方
- 可自定义访问权限和有效期限
- 凭证过期后自动失效,无需手动撤销
STS临时授权的典型流程
以企业A授权企业B上传数据到OSS为例:
步骤一:企业A创建RAM用户,并授予该用户调用STS服务 AssumeRole 接口的权限(AliyunSTSAssumeRoleAccess系统策略)。
步骤二:企业A创建RAM角色,定义该角色被扮演时可以拥有的OSS访问权限。
步骤三:企业A调用STS AssumeRole 接口获取临时访问凭证(包括临时AccessKey ID、AccessKey Secret和SecurityToken),并将其传递给企业B。
步骤四:企业B使用临时凭证构造签名请求,访问OSS资源。临时凭证的有效时间最小为900秒,最大值以角色设定的最大会话时间为准。
使用STS临时凭证的注意事项
当使用STS临时账号生成预签名URL时,有效时长以两者中较小者为准。例如,STS临时凭证有效期为1200秒,预签名URL设置为3600秒,则实际有效期为1200秒。
OSS控制台中默认的URL有效时间为3600秒,最大值为32400秒。如果需要超过32400秒的有效期,必须使用ossutil或OSS SDK生成。
四、综合安全策略与最佳实践
4.1 多层防护的组合使用
单一的安全措施往往不够,建议将多种手段组合使用:
第一层:Bucket ACL设置为私有,确保默认情况下所有数据不公开。
第二层:配置Referer防盗链,防止其他网站盗用资源。
第三层:使用Bucket Policy或RAM Policy进行精细化权限控制,明确谁可以访问什么。
第四层:对于临时访问需求,使用签名URL或STS临时凭证,严格控制有效时间。
4.2 成本优化与安全加固
防盗链不仅是安全手段,也是成本控制手段。恶意盗链会导致大量的外网下行流量费用。建议定期检查OSS的流量监控数据,发现异常流量及时排查是否为盗链行为。
同时,建议启用OSS的日志记录功能,分析访问日志中的Referer字段,及时发现未授权的引用来源。
4.3 最小权限原则
无论是RAM Policy还是Bucket Policy,都应遵循最小权限原则——只授予完成工作所必需的最小权限集。避免使用 AliyunOSSFullAccess 这样的高权限系统策略,而是创建自定义策略,精确控制操作和资源范围。
对于生产环境,建议使用RAM角色和STS临时凭证替代长期AccessKey,减少密钥泄露的风险。
五、常见问题解答
问1:配置了Referer白名单后,为什么我的网站还是无法访问OSS图片?
答:最常见的原因是空Referer策略配置不当。如果您的网站使用HTTPS协议引用HTTP资源,或者用户使用隐私模式浏览器,请求可能不携带Referer。请检查防盗链配置中是否选择了"允许空Referer"。另外,请确认白名单中的域名是否同时包含了 http 和 https 两种协议。
问2:Bucket Policy和RAM Policy有什么区别?我应该用哪个?
答:Bucket Policy是基于资源的授权策略,直接附加在Bucket上,适合"谁可以访问这个Bucket"的场景(如跨账号授权、IP限制)。RAM Policy是基于身份的授权策略,附加在用户/角色上,适合"这个用户可以访问什么"的场景(如统一管理某个用户的所有权限)。两者可以同时使用,权限判定遵循"显式拒绝优先"原则。
问3:签名URL的有效期最长可以设置多久?
答:使用V4签名算法时,AccessKey签名URL最长有效期为7天(604800秒);使用STS临时凭证生成的签名URL最长有效期为12小时(43200秒),且以STS凭证的有效期为准。OSS控制台生成的URL默认有效期为3600秒,最大32400秒。
问4:为什么我配置了Bucket Policy基于IP限制访问后,某些请求仍然被拒绝?
答:首先检查acs:SourceIp条件是否正确配置了目标IP地址。其次,acs:SourceIp仅匹配源IP,不区分公网还是VPC内网。建议同时配置acs:SourceVpc来明确网络来源。另外,如果Bucket Owner自身访问也被拒绝,请检查Principal配置——当Principal为*且包含Condition时,策略对Bucket Owner也生效。
问5:防盗链中的黑名单和白名单同时存在时,哪个优先?
答:OSS会先判断黑名单,再判断白名单。这意味着即使某个域名在白名单中,如果它也在黑名单中,请求会被黑名单规则拦截。
问6:如何防止OSS资源被恶意刷流量?
答:建议从以下几个方面入手:1)Bucket ACL设置为私有,避免公开可读;2)配置Referer防盗链,限制仅允许特定域名引用;3)使用Bucket Policy限制访问IP范围;4)对敏感文件使用签名URL,控制访问时效;5)开启OSS的监控告警,及时发现异常流量。



