『哈希值』遇到CDN劫持怎么办?SRI教你一绝永患


网站安全那点事:令人憎恨的流量劫持
?其一:CDN 劫持
在现代网站建设中 , CDN的使用已经变得非常普及 , 但是CDN会存在被劫持的问题 , 下面就是一次CDN劫持的经历:
突然发现网页某个js没办法运行 , js报错 , 查看后发现因为HTTPS资源中混入了HTTP资源 , 所以导致报错 , js无法运行 , 可是官网的所有资源都是https的怎么会出现了HTTP资源 , 检查发现我们的一个原始文件被替换为
『哈希值』遇到CDN劫持怎么办?SRI教你一绝永患
本文插图
分析发现 , 这段代码将我们的资源重新加载(coedu.js) , 并且添加了自己的资源 , 由于资源是HTTP协议 , 所以出现了上述情况 。
但是为什么我们的原始文件内容变成了这样 , 分析后发现原因应该是CDN劫持(回源过程中) , 当我们访问某个资源时会去附近的CDN节点上进行访问 , 如果这个资源存在则使用CDN上的这个资源 , 这个过程是HTTPS加密的 , 所以不存在劫持 , 可是当我们的资源发生了变化 , 或者是CDN上没有这个资源 , 那么就会去源节点上去寻找这个资源 , 并且拉取到这个CDN上 , 这个过程就是回源 , 回源的这个过程是HTTP的 , 所以这个过程存在风险 , 资源在这个过程中有被篡改或者替换的可能 。
【『哈希值』遇到CDN劫持怎么办?SRI教你一绝永患】
『哈希值』遇到CDN劫持怎么办?SRI教你一绝永患
本文插图
那么我们应该怎么应对这种情况呢 , 这里我就要提一提SRI了 。
SRI简介
SRI全称 Subresource Integrity - 子资源完整性 , 是指浏览器通过验证资源的完整性(通常从 CDN 获取)来判断其是否被篡改的安全特性 。
通过给 link 标签或者 script 标签增加 integrity 属性即可开启 SRI 功能 , 比如:
integrity 值分成两个部分 , 第一部分指定哈希值的生成算法(sha256、sha384 及 sha512) , 第二部分是经过 base64 编码的实际哈希值 , 两者之间通过一个短横(-)分割 。 integrity 值可以包含多个由空格分隔的哈希值 , 只要文件匹配其中任意一个哈希值 , 就可以通过校验并加载该资源 。 上述例子中我使用了 sha256 和 sha384 两种 hash 方案 。
浏览器如何处理 SRI
当浏览器在 script 或者 link 标签中遇到 integrity 属性之后 , 会在执行脚本或者应用样式表之前对比所加载文件的哈希值和期望的哈希值 。
当脚本或者样式表的哈希值和期望的不一致时 , 浏览器必须拒绝执行脚本或者应用样式表 , 并且必须返回一个网络错误说明获得脚本或样式表失败 。
在webpack中使用 SRI
『哈希值』遇到CDN劫持怎么办?SRI教你一绝永患
本文插图
那么当 script 或者 link 资源 SRI 校验失败的时候应该怎么做呢?
比较好的方式是通过 script 的 onerror 事件 , 当遇到 onerror 的时候重新 load 静态文件服务器之间的资源:
『哈希值』遇到CDN劫持怎么办?SRI教你一绝永患
本文插图
在此之前注入以下代码:
『哈希值』遇到CDN劫持怎么办?SRI教你一绝永患
本文插图
比较痛苦的是 onerror 中的 event 中无法区分究竟是什么原因导致的错误 , 可能是资源不存在 , 也可能是 SRI 校验失败 , 当然出现最多的还是请求超时 , 不过目前来看 , 除非有统计需求 , 无差别对待并没有多大问题 。
注入 onerror 事件:
当然 , 由于项目中的 script 标签是由 webpack 打包进去的 , 所以我们要使用 script-ext-html-webpack-plugin 将 onerror 事件和 onsuccess 事件注入进去:


推荐阅读