在XSS终结者一文中,讲述了CSP基础语法组成与使用方式。最终我们利用CSP提供的域名白名单机制,有效地将异常的外联脚本拦在门外。然而在线上环境千千万万,虽然我们限制了外联脚本,但是内联脚本却钻了空。
CSP unsafe-inline
CSP的默认策略是不允许inline脚本执行,所以当我们没有必要进行脚本inline时,CSP域名白名单的机制足以防范注入脚本的问题。然而在实际项目中,我们还是会因为一些场景需要将部分脚本进行inline。于是需要在CSP的规则中增加script-src‘unsafe-inline’
配置允许inline资源执行。但也带来了新的隐患。
允许inline资源执行,也意味着当恶意代码通过inline的方式注入到页面中执行时,页面将变得不再安全。如富文本中被插入一段script代码(没被转义),或者是通过浏览器插件的方式进行代码注入等方式。
Content-Security-Policy: script-src 'unsafe-inline'
CSP nonce
为了避免上述问题,我们可以使用nonce
方式加强的CSP策略,nonce方式是至每次页面访问都产生一个唯一id,通过给内联脚本增加一个nonce属性,并且使其属性值(id)与返回的CSP nonce-{id}对应。只有当两者一致时,对应的内敛脚本才被允许执行。于是,即使网页被注入异常的脚本,因为攻击者不知道当时的nonce的随机id值,所以注入的脚本不会被执行。从而让网页变得更加安全。
1 |
|
那么,当我们通过动态生成脚本并进行插入时,nonce也会将我们正常的代码拦截在外。所以在这种场景下,我们需要配套使用CSP提供的strict-dynamic
,strict-dynamic
模式允许让被信任的脚本插入并放行正常的脚本执行。
Content-Security-Policy:script-src 'nonce-5fAiFfSghuhdf' 'strict-dynamic'
Nonce的部署方式
前端
script标签增加nonce属性
我们可以通过构建的方式为页面中script标签添加nonce属性,并增加一个占位符,如
1 |
|
后端
生产唯一id,在CSP返回头中添加nonce-{id}并将id替换html上的nonce占位符
方式一: 服务端处理
- 当也买你在服务端渲染时,html作为模板在服务端进行处理后输出,我们可以在后端胜场威一id
- 通过模板变量将id注入到html中实现替换NONCE_TOKEN占位符
- 于此同时,将CSP返回头进行对应设置
方式二: Nginx处理
- Nginx中可以使用内置变量的
$request_id
作为唯一id,而当nginx版本不支持时,则可以借助lua去生产一个uuid - 接着通过Nginx的sub_filter NONCE_TOKEN ‘id’ 将页面中的NONCE_TOKEN占位符替换为id,或者使用lua进行替换
- 最后使用
add_header Content-Security-Policy "script-src 'nonce-{id}'"...
添加对应的CSP返回头
当然,为了避免攻击者提前注入一段脚本,并在script标签上同样添加了nonce="NONCE_TOKEN"
后端的“误”替换,导致这段提前注入的脚本进行执行。我们需要保密好项目的占位符,取一个特殊的占位符,并行动起来吧。
- 本文标题:csp-nonce 守护inline Script
- 本文作者:Roy
- 创建时间:2020-10-26 11:12:57
- 本文链接:https://www.yrzdm.com/2020/10/26/csp-nonce/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!