Posted December 18, 2018
#Content Security Policy
内容安全策略(Content-Security-Policy)是W3C的一项重要标准,旨在防止广泛的内容注入攻击,如跨站点脚本(XSS)等。 CSP 有着灵活的白名单控制.
CSP 目前支持的浏览器有
不支持 CSP 的浏览器只会忽略它,如常运行,默认为网页内容使用标准的同源策略。如果网站不提供 CSP 头部,浏览器也使用标准的同源策略(Same origin policy)a 比如: x-frame-options 控制嵌入白名单源, 大多数都是 sameorigin , 表示仅当前主机域名可以嵌入(显然这没必要, 一般嵌入都是外面嵌入)。
CSP 通过指令进行各个安全项控制, 不只是可以对嵌入做控制. 可以参考下面两个文档阅读更多
我最近做的项目是把所有的运维项目合并到一个项目里面, 当然最简单的方式是嵌入, 但在嵌入项目的时候发现了Chrome 控制台这样的错误.
(index):1 Refused to display 'http://xxx.com/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.
显然这是因为sameorigin导致的.
如果我要允许被嵌入, 就要更新 X-Frame-Options 的值. 我们先看看此 Header 支持的写法.
表示该页面可以在相同域名页面的 frame 中展示。
表示该页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许。
表示该页面可以在指定来源的 frame 中展示。
Django 默认是 SameOrigin. 如果其他项目需要嵌入页面, 必须在被嵌入的项目为每个 endpoint 增加 @xframe_options_exempt 装饰器. 此装饰器是移除X-Frame-Options
Response header, 表示此 View 可以嵌入任何页面, 这不符合 OWASP Clickjacking 的建议. 所以我们可以通过ALLOW-FROM uri来指定单个项目来嵌入, 这也是我选择的方案. 或者我可以直接指定 ALLOW_From uri 白名单的形式.
但 Django 没有任何控制项, 可以完成ALLOW-FROM uri
的控制, 虽然可以通过自定义中间件的形式, 或者通过django-xframeoptions第三方项目来设置, 但是我需要嵌入的项目太多, 而且我也不想一个一个的去更新, 这是我想要了在 nginx 上面设置这个header.
于是我在 nginx 配置里面加入.
add_header X-Frame-Options ALLOW-FROM <my uri>;
但事实是增加这个 header 就出现了两个 X-Frame-Options header.
X-Frame-Options: sameorigin;
X-Frame-Options: ALLOW-FROM ;
浏览器对于多个值, 是直接不处理, 并直接拒绝通过此次同源策略的检查.
(index):1 Refused to display 'http://xxx.com' in a frame because it set multiple 'X-Frame-Options' headers with conflicting values ('SAMEORIGIN, ALLOW-FROM '). Falling back to 'deny'.
所以 add_header X-Frame-Options 并不是覆盖, 而且追加到两个 header, 显然这样不行。当然 nginx 上也有其他方式, 去除 SameOrigin 这个值,或者直接更新这个 header. 但我准备采取 CSP, 并移除 X-Frame-Options。
前面提到可以使用 @xframe_options_exempt
装饰器, 移除X-Frame-Options。 但是我要移除所有的视图, 就特别麻烦了。 但可以通过移除django.middleware.clickjacking.XFrameOptionsMiddleware中间件来移除当前项目所有视图的x-Frame-Options。
为什么移除X-Frame-Options? 经过 Chrome71 测试, 当 X-Frame-Options 和 Content-Security-Policy 同时设置, 前者依然作用。
settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# remove this middleware 'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
然后在 nginx 增加, CSP 相关的 Header. 依然是 add_header .
add_header Content-Security-Policy frame-ancestors <my uri>;
以上, 目前 CSP 正在逐渐取代 X-Frame-Options 。 而 X-Frame-Options 将被弃用. 相信在以后的迭代里, Django 将会默认支持 CSP 的控制. 但在目前(2018-12-18)的时间里, 上面的方法可能对你有帮助.