文档首页 > > 用户指南> 域名管理> 配置直播鉴权> Key防盗链

Key防盗链

分享
更新时间: 2019/08/26 16:26

为保障直播资源不被非法盗播,您可以使用直播的Key防盗链功能,在原始播放地址加上鉴权信息。但观众请求播放时,CDN会对其URL带的加密信息进行合法性判断,对非法请求予以拒绝。

工作原理

流程说明如下所示:

  1. 租户在直播控制台开启Key防盗链功能,并配置Key值和时长。
  2. 直播服务将租户配置Key值和时长下发到CDN节点中。
  3. 主播/观众通过租户提供的鉴权推流/播放URL向CDN请求推流或播放。
  4. CDN根据推流或播放URL中携带的鉴权信息校验请求的合法性,仅校验通过的请求会被允许。

开启Key防盗链

  1. 登录视频直播控制台
  2. 在左侧导航树中选择域名管理,进入域名管理页面。
  3. 在需要配置鉴权信息的域名行右侧单击“管理”

  4. 选择鉴权配置 > Key防盗链。在弹出的页面中打“开关”,并配置Key防盗链参数。

    • Key:推流域名和播放域名的加解密密钥。请输入16位的字母和数字。
    • 时长:URL鉴权信息的超时时长,指的是鉴权信息中携带的请求时间与直播服务收到请求时的时间的最大差值,用于检查直播推流URL或者直播播放URL是否已过期,单位:秒,长度限制:1分钟-30天。

  5. 配置完成后,单击“确定”
  6. 提交工单申请Key防盗链配置审核。

    若您修改了Key防盗链相关参数,也需要提交工单重新审核,提交工单时,需要提交的信息如表1所示。

    表1 Key防盗链配置审核

    信息

    说明

    推流域名

    需要配置Key防盗链的直播推流域名。

    示例:test-push.livehwcloud.com

    播放域名

    需要配置Key防盗链的直播播放域名。

    示例:test-play.livehwcloud.com

    Key值

    请填写为4中设置的Key值。

    示例:9wAynnEtvouJwJMs

    时长

    请填写为4中设置的时长。

    示例:0

    IV

    加密使用的IV值,请输入随机生成的16位的字母和数字组合。

    示例:yCmE666N3YAq30SN

    审核通过后,您才可以通过鉴权URL进行推流或播放。请参见鉴权URL生成获取携带鉴权信息的推流和播放地址。

鉴权URL生成

鉴权URL的组成如下所示:

原始地址?auth_info=加密串.EncodedIV

鉴权字段的生成算法如下所示:

LiveID=<AppName>+"/"+<StreamName>
加密串=UrlEncode(Base64(AES128("$"+<Timestamp>+"$"+<LiveID>+"$"+<CheckLevel>)))
EncodedIV=Hex(加密使用的IV)

算法中各加密参数说明如表2所示。

表2 加密参数说明

参数

参数说明

AppName

应用名称,与推流或播放地址中的AppName一致。

StreamName

流名称,与推流或播放地址中的StreamName一致。

LiveID

直播流ID,用于标识唯一的直播流。

Timestamp

鉴权参数生成的UTC时间,格式为“yyyyMMddHHmmss”,用于检查鉴权参数是否已过期,即Timestamp和当前时间差值的绝对值是否大于配置的超时时长。

CheckLevel

检查级别。取值为3或者5。

  • CheckLevel=3,只检查LiveID是否匹配。
  • CheckLevel=5,检查LiveID是否匹配,Timestamp是否超时。

IV

CBC对称加密算法依赖IV向量,随机生成的16位数字和字母组合,IV值长度为128位;CBC模式,PKCS7填充。

鉴权URL示例

rtmp://live.huaweitest1.com/live/8712345?auth_info=z6uwSWUceM2%2FZeDpc2LqjhEFhhXpjQ5IQJhrLoIARQ2%2Bn%2BJV4DrzGRqXxWxMLQBU.44393135353831414132454633374139

其中,z6uwSWUceM2%2FZeDpc2LqjhEFhhXpjQ5IQJhrLoIARQ2%2Bn%2BJV4DrzGRqXxWxMLQBU为加密串,44393135353831414132454633374139为EncodIV。

代码示例

以下以Java demo为例,生成鉴权URL中的“加密串.EncodedIV”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class Main {

        public static void main(String[] args) {

		// data="$"+<Timestamp>+"$"+<LiveID>+"$"+<CheckLevel>,具体请参见“鉴权URL生成”
                String data = "$20190428110000$live/stream01$3";

                // 随机生成的16位数字和字母组合
		byte[] ivBytes = "yCmE666N3YAq30SN".getBytes();

                //在直播控制台配置的Key值
		byte[] key = "MyLiveKeyValue01".getBytes();

                String msg = aesCbcEncrypt(data, ivBytes, key);
		try {
			System.out.println(URLEncoder.encode(msg, "UTF-8") + "." + bytesToHexString(ivBytes));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}

        private static String aesCbcEncrypt(String data, byte[] ivBytes, byte[] key) {
		try {
			SecretKeySpec sk = new SecretKeySpec(key, "AES");
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

                        if (ivBytes != null) {
				cipher.init(Cipher.ENCRYPT_MODE, sk, new IvParameterSpec(ivBytes));
			} else {
				cipher.init(Cipher.ENCRYPT_MODE, sk);
			}

                        return Base64.encode(cipher.doFinal(data.getBytes("UTF-8")));
		} catch (Exception e) {
			return null;
		}
	}

        public static String bytesToHexString(byte[] src) {
		StringBuilder stringBuilder = new StringBuilder("");
		if ((src == null) || (src.length <= 0)) {
			return null;
		}

                for (int i = 0; i < src.length; i++) {
			int v = src[i] & 0xFF;
			String hv = Integer.toHexString(v);
			if (hv.length() < 2) {
				stringBuilder.append(0);
			}
			stringBuilder.append(hv);
		}
		return stringBuilder.toString();
	}
}

以下是Base64类,用于将加密串进行编码。

public class Base64
{

    /** Base64编码表。*/
    private static char base64Code[] =
    {
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
        'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
        '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',};

    /**
     * 构造方法私有化,防止实例化。
     */
    private Base64()
    {
        super();
    }

    /**
     * Base64编码。将字节数组中字节3个一组编码成4个可见字符。
     * @param bytes 需要被编码的字节数据。
     * @return 编码后的Base64字符串。
     */
    public static String encode(byte[] bytes)
    {
        int a = 0;

        // 按实际编码后长度开辟内存,加快速度
        StringBuffer buffer = new StringBuffer(((bytes.length - 1) / 3) << 2 + 4);

        // 进行编码
        for (int i = 0; i < bytes.length; i++)
        {
            a |= (bytes[i] << (16 - i % 3 * 8)) & (0xff << (16 - i % 3 * 8));
            if (i % 3 == 2 || i == bytes.length - 1)
            {
                buffer.append(Base64.base64Code[(a & 0xfc0000) >>> 18]);
                buffer.append(Base64.base64Code[(a & 0x3f000) >>> 12]);
                buffer.append(Base64.base64Code[(a & 0xfc0) >>> 6]);
                buffer.append(Base64.base64Code[a & 0x3f]);
                a = 0;
            }
        }

        // 对于长度非3的整数倍的字节数组,编码前先补0,编码后结尾处编码用=代替,
        // =的个数和短缺的长度一致,以此来标识出数据实际长度
        if (bytes.length % 3 > 0)
        {
            buffer.setCharAt(buffer.length() - 1, '=');
        }
        if (bytes.length % 3 == 1)
        {
            buffer.setCharAt(buffer.length() - 2, '=');
        }
        return buffer.toString();
    }

}
分享:

    相关文档

    相关产品

文档是否有解决您的问题?

提交成功!

非常感谢您的反馈,我们会继续努力做到更好!

反馈提交失败,请稍后再试!

*必选

请至少选择或填写一项反馈信息

字符长度不能超过200

提交反馈 取消

如您有其它疑问,您也可以通过华为云社区问答频道来与我们联系探讨

跳转到云社区