CSP 是什么
CSP 全称 Content Security Policy,直接翻译过来就是‘内容安全策略’。它能帮助开发者保护自己的页面不受外部攻击,和保护资源不被盗用。我们都知道跨域请求限制,CSP 则是比跨域限制来得更猛烈的内容限制策略。它可以限制到页面是否可以加载并执行 JS 脚本,是否可以加载图片,是否可以加载样式单。它也可以控制表单是否可以提交,页面是否可以跳转,是否可以弹窗。总之,有了 CSP 之后我们可以更加灵活的控制一个页面加载资源的行为
常见的 CSP 设置
CSP 如何设置
可以通过后端在响应的 Header 头中添加
Content-Security-Policy: 策略1; 策略2
也可以通过 HTML META 便签进行添加<meta http-equiv="Content-Security-Policy" content="策略1;策略2">。
策略可以有如下设置:
关于拉取资源的控制
default-src
这个是所有资源默认的拉取策略设置,当没有配置的话就会使用这个默认配置。配置示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'" />
<title>Test CSP</title>
</head>
<body>
<img src="https://freepngimg.com/static/img/cat/tree.png" />
</body>
</html>
如果我们在页面加入了不属于当前域名的图片时,图片请求就会被浏览器拒绝了,从而导致图片加载失败,如下:
xxx-src 的值常用配置成如下: 1.self :只能和当前同域 2.unsafe-inline: 可以通过行内运算得到 3.none:不匹配任何,就是完全不允许
img-src
配置当前页面 img src 可以拉取的资源。如果没有配置,那就使用默认配置,如上面的示例。这里我们改配置来支持我们要拉取的图片。
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://freepngimg.com/ " />
<title>Test CSP</title>
</head>
<body>
<img src="https://freepngimg.com/static/img/cat/tree.png" />
</body>
</html>
可以看到报错消失了,图片出来了
child-src
配置当前页面可以通过 web worker、iframe 拉取的资源。如果没有配置,那么使用默认配置 default-src。概念一样就不做示例了。
connect-src
控制我们通过 fetch(), XMLHttpRequest, WebSocket, EventSource, Navigator.sendBeacon() 等 API 请求外部资源的资源地址。
font-src
控制页面可以加载的字体地址
frame-src
控制页面中 iFrame 可以加载的地址
manifest-src
控制页面可以链接的 manifest 文件地址
media-src
控制页面中 video、audio 可以加载的媒体资源地址
object-src
控制页面中 object, embed 便签可以加载的地址
prefetch-src
控制预加载资源的地址
script-src
控制页面中可以加载的脚本地址
style-src
控制页面中可以加载的样式地址
worker-src
控制 Worker, SharedWorker, ServiceWorker 可以加载的脚本地址
关于页面行为的控制
base-uri
我们知道在 html 文件 head 标签内添加 base 标签可以指定页面中所有相对路径是基于我们设定值。如我们 example.com 的 html 如下:
<base href="https://example.com/resources">
...
<img src='/a.png'>
这里的图片 a.png 就会解析为 example.com/resources/a… 。 如果我们配置了如下:
<meta http-equiv="Content-Security-Policy" content="base-uri 'self'" />
<base href="http://127.0.0.1:5500/" />
那么当这个页面的地址不是 base 设置的值时(如 localhost),就会报错 bas e 设置失败。
当从 http://127.0.0.1:5500 打开时,就不会报错了
sandbox
不同于 iFrame 的 sandbox,用于控制 iframe 加载的页面可以有的行为, CSP sandbox 直接控制页面在浏览器中的可以有的行为。能配置的值和 iFrame sandbox 一样。
CSP sanbox 会让整个页面如运行在沙盒一般,可以控制是否允许执行脚本、是否允许弹窗、是否允许下载。它可以配置如下一些值:allow-download、allow-forms、allow-modals、allow-popup、allow-script、allow-top-navigation 等。
sanbox 只会通过后端设置的 header 头才有效果,配置页面 sandobox 不会影响脚本执行,如下
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test CSP</title>
<meta http-equiv="Content-Security-Policy" content="sandbox" />
</head>
<body>
<img src="https://freepngimg.com/static/img/cat/tree.png" />
</body>
<script>
console.log('hello world');
</script>
</html>
可以看到尽管有报错提醒,但是脚本依然得到执行了。
这里看一下通过后端设置 header 报错,并无法执行脚本的场景:
只要我们在后端设置 header 中加上 allow-scripts,就不会有报错了,并且脚本可以执行了,如下:
关于 sandbox 更多请参考 CDN
frame-ancestors
用于指定当前页面的可以在哪些父页面通过如 iframe、embed 之类的标签进行加载。如果当前指父页面为 self 即和页面本身的域名一致,那么在其他网站通过 iframe 是无法加载当前页面的。如果设置为 none,那么这个页面就不能通过任何 iframe 加载,和设置 X-Frame-Options: DENY header 头效果一样。
这个也不支持通过 meta 进行设置。
看看报错效果:
总结
CSP 对于保护我们的网站资源和提升网站安全性非常有帮助,可以多熟悉熟悉,学习学习,了解了解。