OSS支持对云盒Bucket设置防盗链,即通过对访问来源设置白名单的机制,避免OSS资源被其他人盗用。

功能介绍

防盗链功能通过设置Referer白名单以及是否允许空Referer,限制仅白名单中的域名可以访问您Bucket内的资源。OSS支持基于HTTP和HTTPS header中表头字段Referer的方法设置防盗链。

是否进行防盗链验证的具体场景如下:

  • 仅当通过签名URL或者匿名访问Object时,进行防盗链验证。
  • 当请求的Header中包含Authorization字段,不进行防盗链验证。
防盗链通过请求Header中的Referer地址判断访问来源。当浏览器向Web服务器发送请求的时候,请求Header中将包含Referer,用于告知Web服务器该请求的页面链接来源。OSS根据浏览器附带的Referer与用户配置的Referer规则来判断允许或拒绝此请求,如果Referer一致,则OSS将允许该请求的访问;如果Referer不一致,则OSS将拒绝该请求的访问。例如,某个Bucket设置了Referer为 https://10.10.10.10
  • 用户A在https://10.10.10.10嵌入test.jpg图片,当浏览器请求访问此图片时会带上https://10.10.10.10的Referer,此场景下OSS将允许该请求的访问。
  • 用户B盗用了test.jpg的图片链接并将其嵌入https://192.168.0.0,当浏览器请求访问此图片时会带上https://192.168.0.0的Referer,此场景下OSS将拒绝该请求的访问。

Referer配置规则

  • 单个Bucket支持配置多个Referer。通过控制台设置Referer时,使用回车作为换行符分隔;通过API设置Referer时,使用英文逗号(,)分隔。
  • Referer支持使用通配符星号(*)和问号(?)。
    • 通配符星号(*)表示使用星号代替0个或多个字符。如果Referer白名单配置为*.aliyun.com,且不允许空Referer的情况下,则只有HTTP或HTTPS header中包含Referer字段的请求才能访问OSS资源,例如help.aliyun.comwww.aliyun.com等;如果Referer白名单配置为*.aliyun.com,且允许空Referer的情况下,则Referer为空的请求也允许访问OSS资源。
    • 通配符问号(?)表示使用问号代替一个字符。如果设置了包含通配符问号(?)的Referer白名单,且不允许空Referer的情况下,则只有HTTP或HTTPS Header中包含Referer字段的请求才能访问OSS资源。如果设置了包含通配符问号(?)的Referer白名单,且允许空Referer的情况下,则Referer为空的请求也允许访问OSS资源。
  • Referer支持使用反斜线(\)对通配符星号(*)和问号(?)进行转义。
  • Referer默认截断QueryString。如有特殊需求,可设置不允许截断QueryString。

    例如,Referer设置为http://www.example.com/?action=nop,由于OSS匹配该Referer时默认截断QueryString,即使用http://www.example.com/进行匹配。如果希望OSS使用http://www.example.com/?action=nop进行Referer匹配,请通过设置AllowTruncateQueryString参数为false实现不允许截断QueryString。关于设置不允许截断QueryString的具体操作,请参见PutBucketReferer

    设置不允许截断QueryString时,Referer匹配规则有以下注意事项:

    • 不解码QueryString
      通过 http://www.example.com/?job_id=task$01访问OSS时,可能该访问URL会被继续保留为 http://www.example.com/?job_id=task$01,也可能被转义为 http://www.example.com/?job_id=task%2401。通过Referer进行匹配时,不会对访问URL中的QueryString进行解码,示例如下:
      • 当Referer设置为http://www.example.com/?job_id=task%2401的情况下,通过http://www.example.com/?job_id=task$01请求访问OSS时,OSS将拒绝该请求。
      • 当Referer设置为http://www.example.com/?job_id=task$01的情况下,通过http://www.example.com/?job_id=task%2401请求访问OSS时,OSS将拒绝该请求。
    • 忽略QueryString中的参数大小写

      通过Referer进行匹配时,会忽略QueryString中的大小写。即当Referer设置为http://www.example.com/?action=nop的情况下,通过http://www.examplecom/?ACTION=NOP请求访问OSS时,OSS将允许该请求。

    • 不解析QueryString中的参数

      默认情况下,浏览器会将http://example.com/?a=b&b=chttp://example.com/?b=c&a=b视为相同的访问URL。但是通过Referer进行匹配时,不会对QueryString中的参数进行解析,因此http://example.com/?a=b&b=chttp://example.com/?b=c&a=b会被视为不同的访问URL。即当Referer设置为http://example.com/?a=b&b=c的情况下,通过http://example.com/?b=c&a=b请求访问OSS时,OSS将拒绝该请求。

Referer配置效果

  • 如果Referer白名单为通配符星号(*),且不允许空Referer,则带Referer且Referer不为空的请求会被允许。
  • 如果Referer白名单为通配符星号(*),且允许空Referer,则带Referer且Referer为空的请求会被允许。
  • 如果Referer白名单不为通配符星号(*),且不允许空Referer,则只有Referer属于白名单的请求被允许,其他请求(包括Referer为空的请求)会被拒绝。
  • 如果Referer白名单不为通配符星号(*),但允许空Referer,则Referer为空的请求和符合白名单的请求会被允许,其他请求都会被拒绝。

云盒Bucket

  1. 登录OSS管理控制台
  2. 在左侧导航栏,单击云盒Bucket,然后单击目标Bucket名称。
  3. 在左侧导航栏,选择数据安全 > 防盗链
  4. 防盗链页面,打开防盗链开关。
    • Referer输入框中,填写域名或IP地址,支持通配符星号(*)和问号(?),多个Referer以换行分隔。示例如下:
      • 配置为www.aliyun.com,可匹配如www.aliyun.com/123www.aliyun.com.cn等以www.aliyun.com为前缀的地址。
      • 通配符星号(*)表示使用星号代替0个或多个字符。例如配置为*www.aliyun.com/,可匹配如http://www.aliyun.com/https://www.aliyun.com/地址。配置为*.aliyun.com,可匹配如help.aliyun.comwww.aliyun.com等地址。
      • 通配符问号(?)表示使用问号代替一个字符。
      • 支持带端口的域名或IP地址,例如www.example.com:808010.10.10.10:8080等地址。
    • 空Referer区域,选择是否允许Referer为空。

      空Referer表示HTTP或HTTPS请求中,不带Referer字段或Referer字段为空。

      如果不允许空Referer,则只有HTTP或HTTPS Header中包含Referer字段的请求才能访问OSS资源。

      说明 当您使用OSS的云盒Bucket域名(例如examplebucket.cb-f8z7yvzgwfkl9q0h****.cn-hangzhou.oss-cloudbox-control.aliyuncs.com)预览MP4文件时,由于浏览器默认会同时发出两个请求,其中一个为带Referer的请求,另一个为空Referer的请求,因此设置防盗链时必须同时满足在Referer中添加Bucket域名,且允许空Referer的条件。当您使用OSS的Bucket域名预览非MP4文件时,则仅需允许空Referer。
    • 截断QueryString区域,选择是否允许截断QueryString。
  5. 单击保存

使用阿里云SDK

仅支持通过Java SDK设置防盗链,Java SDK要求3.15.0及以上版本。

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.BucketReferer;
import java.util.ArrayList;
import java.util.List;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.ClientBuilderConfiguration;

public class Demo {

    public static void main(String[] args) throws Exception {
        // 填写云盒Bucket的数据域名。
        String endpoint = "https://cb-f8z7yvzgwfkl9q0h****.cn-hangzhou.oss-cloudbox.aliyuncs.com";
        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
        String accessKeyId = "yourAccessKeyId";
        String accessKeySecret = "yourAccessKeySecret";
        // 填写云盒Bucket名称,例如examplebucket。
        String bucketName = "examplebucket";
        // 填写云盒Bucket所在地域。
        String region = "cn-hangzhou";
        // 填写云盒ID。
        String cloudBoxId = "cb-f8z7yvzgwfkl9q0h****";

        // 创建OSSClient实例。
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        conf.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(new DefaultCredentialProvider(accessKeyId, accessKeySecret))
                .clientConfiguration(conf)
                .region(region)
                .cloudBoxId(cloudBoxId)
                .build();

        try {
            List<String> refererList = new ArrayList<String>();
            // 添加Referer白名单。Referer参数支持通配符星号(*)和问号(?)。
            refererList.add("http://www.aliyun.com");
            refererList.add("http://www.*.com");
            refererList.add("http://www.?.aliyuncs.com");
            // 设置Referer列表。设置为true表示Referer字段允许为空,设置为false表示Referer字段不允许为空。
            BucketReferer br = new BucketReferer(true, refererList);
            ossClient.setBucketReferer(bucketName, br);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

使用命令行工具ossutil

关于使用ossutil设置防盗链的具体操作, 请参见添加或修改防盗链配置

使用REST API

如果您的程序自定义要求较高,您可以直接发起REST API请求。直接发起REST API请求需要手动编写代码计算签名。更多信息,请参见PutBucketReferer

更多参考

  • 当您需要限定符合特定条件的用户能够访问您云盒Bucket内的全部或部分资源、对资源授予相关操作权限等,建议您使用Bucket Policy。例如您可以通过配置Bucket Policy的来源IP,限制符合指定IP或IP地址段的用户才能访问某个云盒Bucket。关于配置Bucket Policy的具体操作,请参见Bucket Policy
  • 关于验证防盗链是否生效的更多信息,请参见OSS验证防盗链是否生效
  • 关于使用防盗链过程中遇到的常见问题,请参见OSS防盗链(Referer)配置及错误排除