You can configure hotlink protection for your Object Storage Service (OSS) bucket to prevent your resources in the bucket from unauthorized access.

Background information

The hotlink protection feature allows you to configure a Referer whitelist for a bucket and select whether to allow the empty Referer field. This way, only requests from the domain names that are included in the Referer whitelist can access data in the bucket. You can configure Referer whitelists based on the Referer header field in HTTP and HTTPS requests.

The following scenarios describe whether to use hotlink protection to verify access to OSS:

  • Only anonymous requests and requests that contain signed URLs are verified.
  • Requests that contain the Authorization header field are not verified.
OSS determines the source from which a request is sent based on the Referer header field in the request. When a browser sends a request to the web server, the Referer header field is contained in the request to indicate the source from which the request is sent. OSS determines whether to allow the request based on the Referer header field contained in the request and the Referer whitelist configured for the specified bucket. If the Referer header field in the request matches the Referer whitelist, the request is allowed. Otherwise, the request is denied. For example, if the Referer whitelist for a bucket is set to https://10.10.10.10, you may encounter the following scenarios:
  • User A adds an image object named test.jpg to the https://10.10.10.10 website. When a user accesses the image on the website, the browser sends a request in which the value of the Referer header field is https://10.10.10.10. OSS allows the request because the Referer header field in the request is included in the Referer whitelist.
  • User B adds the URL of the image object to the https://192.168.0.0 website without authorization. When a user accesses the image on the website, the browser sends a request in which the value of the Referer header field is https://192.168.0.0. OSS denies the request because the Referer header field in the request is not included in the Referer whitelist.

Referer configuration rules

  • You can configure multiple Referers for a bucket. When you configure Referers in the OSS console, press the Enter key to separate Referers with line feeds. When you call API operations to configure Referers, use commas (,) to separate Referers.
  • You can use asterisks (*) and question marks (?) as wildcards in Referers.
    • An asterisk (*) can be used as a wildcard to indicate zero or multiple characters. For example, if you add *.aliyun.com to the Referer whitelist of a bucket and deny empty Referers, only HTTP or HTTPS requests in which the Referer header field contains aliyun.com are allowed to access resources in the bucket, such as help.aliyun.com and www.aliyun.com. If you add *.aliyun.com to the Referer whitelist and allow empty Referers, requests in which the Referer header field is empty are also allowed to access resources in the bucket.
    • A question mark (?) can be used as a wildcard to indicate a character. If you add a Referer that contains a question mark as a wildcard character to the Referer whitelist and deny empty Referers, only HTTP or HTTPS requests in which the Referer header field is contained are allowed to access resources in the bucket. If you add a Referer that contains a question mark (?) as a wildcard character to the Referer whitelist and allow empty Referers, requests in which the Referer header field is empty are also allowed to access resources in the bucket.
  • You can use backslashes (\) to escape the asterisk (*) and question mark (?) wildcards in Referers.
  • By default, query strings are truncated in Referers. You can specify that query strings cannot be truncated based on your business requirements.

    For example, if you add http://www.example.com/?action=nop to a Referer whitelist, OSS uses http://www.example.com/ to compare the Referer with the request URL because query strings are truncated by default. If you want OSS to use http://www.example.com/?action=nop to compare the Referer with the request URL, set AllowTruncateQueryString to false to disable query string truncation. For more information about how to disable query string truncation, see PutBucketReferer.

    Take note of the following items when you disable query string truncation:

    • Query strings are not decoded.
      If you use http://www.example.com/?job_id=task$01 to access OSS, the request URL may be retained as http://www.example.com/?job_id=task$01 or be URL-encoded into http://www.example.com/?job_id=task%2401. However, OSS does not decode query strings in request URLs when OSS compares Referers with request URLs. Examples:
      • When the Referer is set to http://www.example.com/?job_id=task%2401, OSS denies the access from http://www.example.com/?job_id=task$01.
      • When the Referer is set to http://www.example.com/?job_id=task$01, OSS denies the access from http://www.example.com/?job_id=task%2401.
    • Fields contained in query strings are not case-sensitive.

      When OSS compares Referers in the whitelist with request URLs, fields contained in query strings are not case-sensitive. For example, when the Referer is set to http://www.example.com/?action=nop, OSS allows the access from http://www.example.com/?ACTION=NOP.

    • Fields contained in query strings are not parsed.

      By default, browsers consider http://example.com/?a=b&b=c and http://example.com/?b=c&a=b as identical URLs. However, when OSS compares Referers in the whitelist with request URLs, fields contained in query strings are not parsed. Therefore, http://example.com/?a=b&b=c and http://example.com/?b=c&a=b are considered as different URLs. In other words, when the Referer is set to http://example.com/?a=b&b=c, OSS denies the access from http://example.com/?b=c&a=b.

Effects of Referer configurations

  • If the Referer whitelist is empty, all requests are allowed.
  • If the Referer whitelist is not empty and empty Referers are not allowed, only requests that contain the Referers specified in the whitelist are allowed.
  • If the Referer whitelist is not empty and empty Referers are allowed, only requests that contain the Referers specified in the whitelist or contain empty Referers are allowed.

Use the OSS console

  1. Log on to the OSS console.
  2. In the left-side navigation pane, click Buckets. On the Buckets page, click the name of the bucket that you want to manage.
  3. In the left-side navigation pane, choose Access Control > Hotlink Protection.
  4. In the Hotlink Protection section, click Configure.
    • Enter domain names or IP addresses in the Referer Whitelist field. Separate multiple Referers with line feeds. You can use asterisks (*) and question marks (?) as wildcards. Examples:
      • If you add www.aliyun.com to the Referer whitelist, requests sent from URLs that start with www.aliyun.com, such as www.aliyun.com/123 and www.aliyun.com.cn are allowed.
      • An asterisk (*) can be used as a wildcard for zero or multiple characters. If you add *www.aliyun.com/ to the Referer whitelist, requests sent from http://www.aliyun.com/ and https://www.aliyun.com/ are allowed. For example, if you add *.aliyun.com to the Referer whitelist, requests sent from URLs such as help.aliyun.com and www.aliyun.com are allowed.
      • A question mark (?) can be used as a wildcard for a single character.
      • You can add domain names or IP addresses that include a port number, such as www.example.com:8080 and 10.10.10.10:8080, to the Referer whitelist.
    • Select whether to turn on Allow Empty Referer to allow requests in which the Referer field is empty.

      An HTTP or HTTPS request that contains an empty Referer indicates that the request does not contain the Referer field or that the value of the Referer field is empty.

      If you turn off Allow Empty Referer, only HTTP or HTTPS requests that include an allowed Referer field can access the objects in the bucket.

      Note By default, if you preview an MP4 object by using a bucket domain name such as bucketname.oss-cn-zhangjiakou.aliyuncs.com, the browser simultaneously sends two requests. One request contains the Referer field, and the other does not. Therefore, you must add the bucket domain name to the Referer whitelist and allow empty Referer fields. To preview a non-MP4 object by using the bucket domain name, you need to only allow empty Referer fields.
    • Select whether to turn on Truncate QueryString to allow query strings to be truncated.
  5. Click Save.

Use OSS SDKs

The following code provides examples on how to configure hotlink protection for a bucket by using OSS SDKs for common programming languages. For more information about how to configure hotlink protection for a bucket by using OSS SDKs for other programming languages, see Overview.

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;

public class Demo {

    public static void main(String[] args) throws Exception {
        // In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // Security risks may arise if you use the AccessKey pair of an Alibaba Cloud account to access OSS because the account has permissions on all API operations. We recommend that you use a RAM user to call API operations or perform routine O&M. To create a RAM user, log on to the RAM console. 
        String accessKeyId = "yourAccessKeyId";
        String accessKeySecret = "yourAccessKeySecret";
        // Specify the bucket name. Example: examplebucket. 
        String bucketName = "examplebucket";

        // Create an OSSClient instance. 
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            List<String> refererList = new ArrayList<String>();
            // Add Referers to the Referer whitelist. You can use asterisks (*) and question marks (?) as wildcards in Referers. 
            refererList.add("http://www.aliyun.com");
            refererList.add("http://www.*.com");
            refererList.add("http://www.?.aliyuncs.com");
            // Configure the Referer whitelist of the bucket. If this parameter is set to true, empty Referer fields are allowed. If this parameter is set to false, empty Referer fields are not allowed. 
            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();
            }
        }
    }
}
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\OssClient;
use OSS\Core\OssException;
use OSS\Model\RefererConfig;

// The AccessKey pair of an Alibaba Cloud account has permissions on all API operations. Using these credentials to perform operations in OSS is a high-risk operation. We recommend that you use a RAM user to call API operations or perform routine O&M. To create a RAM user, log on to the RAM console at https://ram.console.aliyun.com. 
$accessKeyId = "<yourAccessKeyId>";
$accessKeySecret = "<yourAccessKeySecret>";
// In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
$endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";

$refererConfig = new RefererConfig();
// Allow empty Referers. 
$refererConfig->setAllowEmptyReferer(true);
// Add Referers to the Referer whitelist. You can use asterisks (*) and question marks (?) as wildcards in Referers. 
$refererConfig->addReferer("example.com");
$refererConfig->addReferer("example.net");
try{
    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);

    $ossClient->putBucketReferer($bucket, $refererConfig);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . ": OK" . "\n");
            
let OSS = require('ali-oss')

let client = new OSS({
  region: '<Your region>'
  accessKeyId: '<Your AccessKeyId>',
  accessKeySecret: '<Your AccessKeySecret>',
  bucket: '<Your bucket name>'
});

async function putBucketReferer () {
  try {
  let result = await client.putBucketReferer('bucket-name', true, [
    'example.com',
    '*.example.com'
  ]);
  console.log(result);
  } catch (e) {
    console.log(e);
  }
 }

putBucketReferer();
            
# -*- coding: utf-8 -*-
import oss2
from oss2.models import BucketReferer

# The AccessKey pair of an Alibaba Cloud account has permissions on all API operations. Using these credentials to perform operations in OSS is a high-risk operation. We recommend that you use a RAM user to call API operations or perform routine O&M. To create a RAM user, log on to the RAM console. 
auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>')
# In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>')

# Set BucketReferer to True. The value of True indicates that empty Referers are allowed and the value of False indicates that empty Referers are not allowed. Then, configure the Referer whitelist. 
bucket.put_bucket_referer(BucketReferer(True, ['http://aliyun.com', 'http://*.aliyuncs.com']))
            
using Aliyun.OSS;
using Aliyun.OSS.Common;
var endpoint = "<yourEndpoint>";
var accessKeyId = "<yourAccessKeyId>";
var accessKeySecret = "<yourAccessKeySecret>";
var bucketName = "<yourBucketName>";
// Create an OSSClient instance. 
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
    var refererList = new List<string>();
    // Add a Referer whitelist. You can use asterisks (*) and question marks (?) as wildcards in Referers. 
    refererList.Add(" http://www.aliyun.com");
    refererList.Add(" http://www.*.com");
    refererList.Add(" http://www.?.aliyuncs.com");
    var srq = new SetBucketRefererRequest(bucketName, refererList);
    // Configure the Referer whitelist. 
    client.SetBucketReferer(srq);
    Console.WriteLine("Set bucket:{0} Referer succeeded ", bucketName);
}
catch (OssException ex)
{
    Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
        ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
}
catch (Exception ex)
{
    Console.WriteLine("Failed with error info: {0}", ex.Message);
}
PutBucketRefererRequest request = new PutBucketRefererRequest();
request.setBucketName("yourBucketName");
// Add a Referer whitelist. You can use an asterisk (*) or a question mark (?) as a wildcard character to set the Referer parameter.
ArrayList<String> referers = new ArrayList<String>();
referers.add("http://example.com");
referers.add("http://www. *.com");
referers.add("http://www.?.com");
request.setReferers(referers);

OSSAsyncTask task = oss.asyncPutBucketReferer(request, new OSSCompletedCallback<PutBucketRefererRequest, PutBucketRefererResult>() {
    @Override
    public void onSuccess(PutBucketRefererRequest request, PutBucketRefererResult result) {
        OSSLog.logInfo("code: " + result.getStatusCode());
    }
    @Override
    public void onFailure(PutBucketRefererRequest request, ClientException clientException, ServiceException serviceException) {
        OSSLog.logError("error: "+serviceException.getRawMessage());
    }
});
task.waitUntilFinished();
package main

import (
    "fmt"
    "os"
    "github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
    // Create an OSSClient instance. 
    client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
    if err!=nil{
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    bucketName := "<yourBucketName>"

    // Add Referers to the Referer whitelist and specify that empty Referer fields are not allowed. You can use an asterisk (*) or a question mark (?) as a wildcard to set the Referer parameter. 
    referers := []string{"http://www.aliyun.com",
                         "http://www.???.aliyuncs.com",
                         "http://www.*.com"}
    err = client.SetBucketReferer(bucketName, referers, false)
    if err!=nil{
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
}            
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;

int main(void)
{
     /* Initialize OSS account information. */
    std::string AccessKeyId = "yourAccessKeyId";
    std::string AccessKeySecret = "yourAccessKeySecret";
    std::string Endpoint = "yourEndpoint";
    std::string BucketName = "yourBucketName";

    /* Initialize resources such as network resources. */
    InitializeSdk();

    ClientConfiguration conf;
    OssClient client(Endpoint, AccessKeyId, AccessKeySecret,  conf) ;

    /* Configure hotlink protection. */
    SetBucketRefererRequest request(BucketName);
    request.addReferer("http://example.com");
    request.addReferer("https://example.com");
    request.addReferer("https://www.?.example.com");
    request.addReferer("https://www.*.cn");
    request.setAllowEmptyReferer(false);

    auto outcome = client.SetBucketReferer(request);

    if (!outcome.isSuccess()) {
        /* Handle exceptions. */
        std::cout << "SetBucketReferer fail" <<
        ",code:" << outcome.error().Code() <<
        ",message:" << outcome.error().Message() <<
        ",requestId:" << outcome.error().RequestId() << std::endl;
        ShutdownSdk();
        return -1;
    }

    /* Release resources such as network resources. */
    ShutdownSdk();
    return 0;
}
#include "oss_api.h"
#include "aos_http_io.h"
const char *endpoint = "<yourEndpoint>";
const char *access_key_id = "<yourAccessKeyId>";
const char *access_key_secret = "<yourAccessKeySecret>";
const char *bucket_name = "<yourBucketName>";
void init_options(oss_request_options_t *options)
{
    options->config = oss_config_create(options->pool);
    /* Use a char* string to initialize the aos_string_t data type. */
    aos_str_set(&options->config->endpoint, endpoint);
    aos_str_set(&options->config->access_key_id, access_key_id);
    aos_str_set(&options->config->access_key_secret, access_key_secret);
    /* Specify whether to use CNAME. The value of 0 indicates that CNAME is not used. */
    options->config->is_cname = 0;
    /* Configure network parameters such as the timeout period. */
    options->ctl = aos_http_controller_create(options->pool, 0);
}
int main(int argc, char *argv[])
{
    /* Call the aos_http_io_initialize method in main() to initialize global resources such as networks and memory. */
    if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
        exit(1);
    }
    /* Create a memory pool to manage memory. aos_pool_t is equivalent to apr_pool_t. The code used to create a memory pool is included in the APR library. */
    aos_pool_t *pool;
    /* Create a memory pool. The second parameter is set to NULL. This value indicates that the pool does not inherit other memory pools. */
    aos_pool_create(&pool, NULL);
    /* Create and initialize options. This parameter includes global configuration information such as endpoint, access_key_id, access_key_secret, is_cname, and curl. */
    oss_request_options_t *oss_client_options;
    /* Allocate the memory resources in the memory pool to the options. */
    oss_client_options = oss_request_options_create(pool);
    /* Initialize oss_client_options. */
    init_options(oss_client_options);
    /* Initialize the parameters. */
    aos_string_t bucket;
    aos_table_t *resp_headers = NULL; 
    aos_status_t *resp_status = NULL;
    oss_referer_config_t referer_config;
    aos_str_set(&bucket, bucket_name);
    aos_list_init(&referer_config.referer_list);
    oss_create_and_add_refer(pool, &referer_config, "http://www.aliyun.com");
    oss_create_and_add_refer(pool, &referer_config, "https://www.aliyun.com");
    referer_config.allow_empty_referer = 0;
    /* Add a Referer whitelist. You can use an asterisk (*) or a question mark (?) as a wildcard character to set the Referer parameter. */
    resp_status = oss_put_bucket_referer(oss_client_options, &bucket, &referer_config, &resp_headers);
    if (aos_status_is_ok(resp_status)) {
        printf("put bucket referer succeeded\n");
    } else {
        printf("put bucket referer failed\n");      
    }
    /* Release the memory pool. This operation releases the memory resources allocated for the request. */
    aos_pool_destroy(pool);
    /* Release the allocated global resources. */
    aos_http_io_deinitialize();
    return 0;
}
require 'aliyun/oss'

client = Aliyun::OSS::Client.new(
  endpoint: 'endpoint',
  access_key_id: 'AccessKeyId', access_key_secret: 'AccessKeySecret')

bucket = client.get_bucket('my-bucket')
bucket.referer = BucketReferer.new(
  allow_empty: true, whitelist: ['example.com', '*.example.com'])
            

Use ossutil

For more information about how to use ossutil to configure hotlink protection, see Add or modify hotlink protection configurations for a bucket.

Use the RESTful API

If your business requires a high level of customization, you can directly call RESTful APIs. To directly call an API, you must include the signature calculation in your code. For more information, see PutBucketReferer

References

  • If you want to allow users that meet specified conditions to access part of or all resources in your bucket or perform specific operations on the resources, we recommend that you configure bucket policies. For example, you can configure a bucket policy to allow only users from specified IP addresses or CIDR blocks to access a specified bucket. For more information about how to configure bucket policies, see Configure bucket policies to authorize other users to access OSS resources.
  • For more information about how to troubleshoot hotlink protection errors, see Referer.