在线教育机构的视频如何做防下载和防盗录?

news/2024/7/3 0:09:48

在线教育平台付费课程、企业内训的培训课程,这类视频课程内容是如何做防下载和防盗录的?

1.AI隐形溯源水印

这个功能能够将水印隐藏在视频中,不会影响观看体验,但却能够帮助企业很好的视频版权保护。更重要的是,对于盗录侵权内容,我们可以通过这个功能做溯源,追踪侵权行为。

 图:AI隐形溯源水印

2.VRM分片错序视频加密

采用分布式编码技术,将视频文件物理切片,每片视频进行多种算法混合型加密, 同时结合独立研制密码本,将关键数据进行错序混淆,对视频文件进行最高级别加密,这样经过加密的视频内容即使被下载,也无法进行恶意的二次分发,视频破解难度倍增。

3.Html5全链路视频加密

市面上常见的H5加密,采用标准的Apple HLS Encryption 视频保护机制,我们在此基础上进行深度优化,对密钥key进行深度加密,同时实现对视频播放器与视频数据文件双重加密处理,形成端到端的全链路视频安全防护,即使视频文件被盗用,其他应用也无法播放,让视频更加安全。

 我们的加密调用方法示例:

<div id="player"></div>
<script src="//player.polyv.net/script/player.js"></script>
<script>
var player = polyvPlayer({
    wrap: '#player',
    width: 800,
    height: 533,
    vid: '88083abbf5bcf1356e05d39666be527a_8',   
    playsafe:'81814fed-bdd0-4506-bec1-ebc8093148c5-hfevwsfxcsbcocx', 
  //playsafeUrl:'https://myDomain.com/token', // 业务方自定义的获取播放凭证接口URL,与playsafe参数二选一
    ts:'1568131545000',
    sign:'88313661ba7ded642c7b557b0a364b4b'
});

//切换加密视频时,需要重新获取播放凭证。如果初始化播放器时使用了playsafeUrl参数,则播放器会自动获取新的凭证,无需传playsafe参数。
player.changeVid({
  vid: '88083abbf5bcf1356e05d39666be527a_9', //需要切换的视频vid
  playsafe: '81814fed-bdd0-4506-bec1-ebc8093148c6-hfevwsfxcsbcocx', //新获取的playsafe token
  sign: '88313661ba7ded642c7b557b0a364b4c', //新获取的sign和ts参数
  ts: '1568131545001'
});
</script>

Web页面播放加密视频前,需要先访问业务方自己的服务端授权验证接口(可以在这里加上自有业务的授权验证逻辑,例如是否登录、是否购买课程等, 建议使用HTTPS)。如果业务上允许播放,则通​ 过创建 Playsafe Token接 ​口获取播放凭证(或者在服务端生成sign、ts参数),并返回给Web端播放器。

服务端生成播放凭证代码示例:

// 接口中应附带自有业务的授权验证逻辑,如判断是否登录、是否购买课程等

// 以下为生成播放凭证的代码示例
function get_client_ip() {
  if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
    $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
  } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
      $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
  } else {
      $ipaddress = $_SERVER['REMOTE_ADDR'];
  }
    return $ipaddress;
}

$userId = 'your userId';       // 保利威点播账号的userId
$secretkey = 'your secretkey';     // 保利威点播账号的secretkey
$videoId = '88083abbf5bcf1356e05d39666be527a_8';  // 视频vid
$ts = time() * 1000;      // 时间戳
$viewerIp = get_client_ip();  // 观众ip
$viewerId = '12345';      // 观众id
$viewerName = 'testUser';  // 观众昵称, 若值为中文需要urlencode('张三')
$extraParams = 'HTML5';  // 自定义扩展参数
$disposable = false // true 表示 token 仅一次有效。false 则表示在有效期内可以多次验证。默认为 false。

/* 将参数 $userId、$secretkey、$videoId、$ts、$viewerIp、$viewerIp、$viewerId、$viewerName、$extraParams按照ASCKII升序 key + value + key + value ... +value 拼接
*/
$concated =  'extraParams'.$extraParams.'ts'.$ts.'userId'.$userId.'videoId'.$videoId.'viewerId'.$viewerId.'viewerIp'.$viewerIp.'viewerName'.$viewerName;
// 首尾加上secretkey值
$plain = $secretkey.$concated.$secretkey;
// 取大写MD5
$sign = strtoupper(md5($plain));

// 然后将下列参数用post请求  https://hls.videocc.net/service/v1/token 获取 token
$url = 'https://hls.videocc.net/service/v1/token';
$data = array('userId' => $userId, 'videoId' => $videoId, 'ts' => $ts, 'viewerIp' => $viewerIp, 'viewerName' => $viewerName, 'extraParams' => $extraParams, 'viewerId' => $viewerId, 'sign' => $sign);
$options = array(
    'http' => array(
        'header'  => "Content-type: application/x-www-form-urlencoded",
        'method'  => 'POST',
        'content' => http_build_query($data)
    )
);
$context  = stream_context_create($options);
$result = file_get_contents($url, false, $context);

// 获取接口返回结果中的token值, 并传给播放器播放加密视频
$token = json_decode($result)->data->token;
echo $token;

Java SpringMvc代码:

@ResponseBody
@RequestMapping("/playerSafe")
public String playerSafe(HttpServletRequest request) {
    String userId = "your userId";       // 保利威点播账号的userId
    String secretkey = "your secretkey";     // 保利威点播账号的secretkey
    String videoId = "88083abbf5bcf1356e05d39666be527a_8";  // 视频vid
    long ts = System.currentTimeMillis();      // 时间戳
    String viewerIp = getClientIp(request);  // 观众ip
    String viewerId = "12345";      // 观众id
    String viewerName = "testUser";  // 观众昵称, 若值为中文需要urlencode('张三')
    String extraParams = "HTML5";  // 自定义扩展参数
    boolean disposable = false; // true 表示 token 仅一次有效。false 则表示在有效期内可以多次验证。默认为 false。

    /* 将参数 userId、secretkey、videoId、ts、viewerIp、viewerIp、viewerId、viewerName、extraParams按照ASCKII升序 key + value + key + value ... +value 拼接
     */
    String concated = "extraParams" + extraParams + "ts" + ts + "userId" + userId + "videoId" + videoId + "viewerId" + viewerId + "viewerIp" + viewerIp + "viewerName" + viewerName;
    // 首尾加上secretkey值
    String plain = secretkey + concated + secretkey;
    // 取大写MD5,可自行选择md5库
    String sign = md5Hex(plain).toUpperCase();

    // 然后将下列参数用post请求  https://hls.videocc.net/service/v1/token 获取 token
    String url = "https://hls.videocc.net/service/v1/token";

    Map<String, String> params = new HashMap<>();
    params.put("userId", userId);
    params.put("videoId", videoId);
    params.put("ts", String.valueOf(ts));
    params.put("viewerIp", viewerIp);
    params.put("viewerName", viewerName);
    params.put("extraParams", extraParams);
    params.put("viewerId", viewerId);
    params.put("sign", sign);
    // 可自行选择http客户端
    String response = HttpClientUtil.getInstance().sendHttpPost(url, params);

    try {
        //解析json
        ObjectMapper objectMapper = new ObjectMapper();
        TokenResponse tokenResponse = objectMapper.readValue(response, TokenResponse.class);
        // 响应代码,200为成功,403为ts过期或签名错误,400为参数错误(例如缺少 userId 或 videoId)
        if (tokenResponse.getCode() == 200) {
            Map data = (Map) tokenResponse.getData();
            return data.get("token").toString();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return "";
}
static class TokenResponse {
    int code;
    String status;
    String message;
    Object data;
    //省略getter、setter...
}
public String getClientIp(HttpServletRequest request) {
    String ip = request.getHeader("x-forwarded-for");
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getRemoteAddr();
    }
    return ip;
}

4.用户ID跑马灯

  图:用户ID跑马灯

将用户I的ID、电话号码或其他信息内容等设置在视频上不规则跑动(作追溯盗版者用)。 ID跑马灯功能,是指通过设定文字内容(一般是观众的身份ID信息)在视频上不规则滚动,以此来警示盗版者,达到视频版权保护的效果,示例中是将用户的ID和电话号码显示出来。

5.数字化动态水印

  图:数字化动态水印

 将用户ID、电话号码或其他信息内容等以动态水印形式展现在视频上,实现水印在视频上不规则地显现,可追溯录屏者身份,对翻录行为起到强有力的震慑作用。

6.浏览器防录屏

 图 / 浏览器防录屏

通过播放器实时监测,如果检测到视频处于录屏状态或小窗待录屏状态,视频会立即停止播放,显示报错信息,视频无法继续播放。

7.视频水印 (企业LOGO)

在视频中添加企业专属的视频水印,从而让视频中融入企业的版权信息,防止盗录者盗取版权,保护公司的知识产权。视频上传后自动将企业的LOGO图标水印加在视频右上角/右下角等位置上。

8.域名白名单​OVP防盗链

通过OVP防盗链技术实现指定网站播放,俗称域名黑白名单。设置网站A白名单,则只允许视频在A网站下播放;设置网站B黑名单,则禁止视频在B网站下播放,可有效防止用户原创视频资源被非法盗用。

9.ATS/HTTPS数据防篡改

HTTPS协议,采用了HTTPS协议,其提供网站身份验证与加密通讯方法,避免信息截韧“钓鱼”攻击,有效防止网页被篡改,保证企业及学员间的信息 安全;ATS标准,苹果操作系统遵循ATS标准,开启ATS安全特性后,网络传输自动通过HTTPS协议进行传输,保证视频播放安全。

10.播放器代码混淆加密

播放器代码加密,防反编译、代码混淆等方式。

11.禁止拖动视频进度条

html5播放器禁止拖拽功能实例(常用于场景:企业培训、在线教学内容禁止学员拖动视频进行观看)。

如果你有更多关于视频加密、视频防录、视频版权保护方面的想法,欢迎在评论区留言与大家一起分享。

  我的文章推荐:

  • [视频+图文] 线上研讨会是什么,企业对内对外培训可以用线上研讨会吗?
  • [图文] 企业直播对网络带宽有什么要求?
  • [图文]OBS如何实现毫秒级超低延时直播
  • 直播播放器API(播放器调用方法、参数、接口和事件)
  • 企业内训课程视频加密防下载是如何做的?10种思路
  • 超低延迟/无延迟直播(PRTC Web SDK移动端)兼容性说明
  • html5视频播放器代码调用实例(视频切换\倍速切换)
  • 企业直播要如何做?硬件设备、网络环境有哪些要求?
  • 企业内训课程视频加密防下载是如何做的?10种思路


http://lihuaxi.xjx100.cn/news/1216015.html

相关文章

驱动开发--驱动模块

目录 1.驱动模块 hello.c Makefile 2.内核中的打印函数&#xff08;编写第一个驱动程序&#xff09; Source Insight 使用&#xff1a; 3.打印函数编写 分析 4、驱动的多文件编译 5、模块传递参数 6、安装好驱动之后如何传参&#xff1f; 7、字符设备驱动 8、字符设…

Shell函数(二):数组

shell函数二-数组 三、数组&#xff1a;1.数组的最大作用&#xff1a;2.应用场景&#xff1a;3.格式&#xff1a;4.数组的数据类型&#xff1a;5.获取数组的长度&#xff1a;6.数组切片&#xff1a;7.数据传参&#xff1a;8.冒泡排序&#xff1a; 三、数组&#xff1a; 1.数组…

SpringCloud-stream一体化MQ解决方案-概念篇

参考资料: 参考demo 参考视频1 参考视频2 官方文档(推荐) 官方文档中文版 关于Kafka和rabbitMQ的安装教程,见本人之前的博客 rocketMq的安装教程

6/5~6/6总结

创建存储过程 DELIMITER // CREATE PROCEDURE usingid() BEGIN SELECT AVG(id) FROM user; END // DELIMITER ; 要用DELIMITER //指定结束符为 "//", 要调用该存储过程&#xff1a; CAll usingid; 创建成功后在navicat里面的函数界面可以看见刚刚创建的存储过程…

传统制作 VS AI制作,如何一键制作PPT ?

教你如何快速的生成一个可用的 PPT&#xff0c;以及现在比较主流的 ChatGPT PPT 衍生工具推荐。 一、原理 结合AI生成 PPT 的原理其实非常简单&#xff0c; 现有的一些 PPT 软件或者开源工具会提供一种文本格式&#xff0c;我们只需要给出定固定的格式&#xff0c;把内容输入…

位运算总结

位运算 有符号整数无符号整数位移运算 1计算机中数字的表示 计算机只有0&#xff0c;1两个数字&#xff0c;所以我们常用的10进制计算 所以我们需表示10进制 要使用二进制来表示10进制数 进制表示法 我们假设一个 8 位的数据类型 方案1 2&#xff1a;0000 0010 我们会发现…

(三)CSharp-方法

一、实例字段和局部变量 实例字段局部变量生存期从实例被创建时开始&#xff0c;直到实例不再被访问时结束从它在块中被声明的那一刻开始&#xff0c;在块完成执行时结束隐式初始化初始化成该类型的默认值没有隐式初始化。如果变量在使用之前没有被赋值&#xff0c;编译器就会…

Azure Log Analytics:与Power BI集成

注&#xff1a;本文最初发布于https://d-bi.gitee.io, 2023年6月迁移至CSDN 前述 Azure Log Analytics是Azure Monitor中的一项分析服务。本文将讲述通过Log Analytics与Power BI集成的方式&#xff0c;获取Power BI工作区内的日志信息&#xff0c;包括各PBI数据集的CPU消耗&a…