FrankKai / FrankKai.github.io

FE blog

Home Page:https://frankkai.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

内容安全策略CSP是什么?

FrankKai opened this issue · comments

当我们谈起如何防范web安全中的XSS攻击时,通常会说:浏览器引入了内容安全策略,也就是CSP(Content Security Policy),去解决XSS攻击的问题。

有人说,CSP的核心**是让服务器决定浏览器能够加载哪些资源,相当于一个前端资源白名单。这样做的目的是抵御XSS攻击,提升前端安全性。

那么CSP到底什么呢?
这句对CSP的概括是否准确呢?

  • CSP前言
  • 面临的威胁
  • 如何使用CSP
  • 示例:常用的使用示例
  • 测试你的策略
  • 开启报告
  • 违规报告语法
  • 违规报告采样
  • CSP指令指南
  • 腾讯AlloyTeam两篇非常好的CSP文章

CSP前言

Content Security Policy(CSP)是一个检测和减轻确定类型攻击的内容安全层,这些确定攻击类型包括XSS(Cross Site Scripting)攻击和数据注入攻击。这些攻击可以造成网站的数据盗窃,网站污损和恶意软件安装。

CSP是完全的向后兼容的(除了CSP2.0版本有一些明显的在兼容性上的问题;更多细节可以看1.1章节)。
服务器实现了CSP而浏览器不支持的,浏览器可以正常工作,但是浏览器会忽略CSP,默认使用标准的web同源策略。如果网站没有提供CSP头,浏览器同样会使用标准的同源策略。

为了开启CSP,你需要配置的web服务器(Apache, Nginx) 去返回Content-Security-Policy HTTP头。(有时你可能会看到X-Content-Security-Policy头,但是这是一个老版本的头,无需关心)

或者,可以使用<meta>标签去配置策略,例如<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*;child-src 'none'; ">

面临的威胁

缓解XSS攻击

设计CSP的一个重要原因就是缓解和报告XSS攻击。XSS利用浏览器对服务器接收的内容的信任发起攻击。因为浏览器信任内容源,所以恶意脚本在受害者的浏览执行,即使内容并不是来自于它应该来自的地方。

CSP通过指定浏览器的源,可以使得服务器管理者减少或者消除XSS发起的攻击。一个CSP兼容的浏览器会只接收在白名单域名下的资源文件,忽略其他脚本(内联脚本或者事件处理html属性)

还有一个最终的保护形式,全局禁止脚本执行可以使得站点上的所有脚本不执行。

缓解数据包嗅探攻击

除了限制哪些源可以加载内容以外,服务器还可以指定哪个协议和端口被使用;例如(来自一个理想的标准端口),一个服务器可以指定所有内容都通过HTTPS加载。一个完整的数据传输安全策略不仅仅包含HTTPS传输数据,也包括通过设置cookie的secure属性并且自动重定向到HTTP页面到HTTPS页面。网站可以使用strict-Transport-SecurityHTTP头去确保只通过加密通过去连接浏览器和服务器。

如何使用CSP

配置内容安全策略主要是通过给网页增加Content-Security-PolicyHTTP头,设置这个头的值可以控制用户端可以加载哪些资源。例如, 一个上传和展示图片的页面,需要允许任何地方的图片都可以展示,但是提交表单的时候需要限制到指定端口。 一个适当设计的内容安全策略可以阻止网站受到XSS攻击。这个文章将解释如何设置内容安全头。

指定你的策略

你可以使用Content-Security-PolicyHTTP头去设置策略,例如:

Content-Security-Policy: policy

policy是一个字符串,用于描述你的内容安全策略。

写一个策略

使用一系列策略指令来描述策略,每个策略指令都描述特定资源类型或策略区域的策略。您的策略应包括default-src策略指令,这是其他资源类型没有自己的策略时的后备(有关完整列表,请参阅default-src指令的说明)。策略需要包括default-src或script-src指令,以防止运行内联脚本以及阻止使用eval()。策略需要包括default-src或style-src指令,以限制从<style>元素或样式属性应用内联样式。有针对各种项目类型的特定指令,因此每种类型都可以有自己的策略,包括字体,框架,图像,音频和视频媒体,脚本和工作程序。

示例:常用的使用示例

网站管理员想要所有的内容都来自自己的origin(排除子域)

Content-Security-Policy: default-src 'self'

网站管理员想要所有的内容来自一个可信域及其子域

Content-Security-Policy: default-src 'self' *.trusted.com

网站管理员想要允许web应用的用户在自己的内容中可以包含任意源的图片,但是限制音频,视频为指定的提供者,所有的脚本文件只能来源于部署了文件的机器

Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com

这里,默认内容只允许来自于当前文档源:

  • 图片来自任意位置,*号通配符
  • 媒体资源可以来源于media1.com和media2.com,不能来源于它们的子网站
  • 可执行脚本只能来源于userscripts.example.com

一家在线银行的网站管理员想要确保所有的内容都是使用TLS加载的,为了抵御请求窃听

Content-Security-Policy: default-src https://onlinebanking.jumbobank.com

一家在线商店的网站管理员想要在电子邮件中允许HTML,图片可以来自于任意源,但是禁止js或者其他有危险的内容

Content-Security-Policy: default-src 'self' *.mailsite.com; img-src *

注意script-src没有被特殊声明,这是因为在CSP这个例子中,已经设定了default-src 'self',这也就意味着这个网站加载的脚本只能来源于自己的服务器

测试你的策略

为了便于部署,CSP可以使用只读模式部署。策略不是强制的,但是任意违规都会报告给提供的URL。另外,仅报告只读头可以用于测试策略的未来修订版,而不用实际部署它。
可以使用Content-Security-Policy-Report-OnlyHTTP头去设置策略:

Content-Security-Policy-Report-Only: policy

如果Content-Security-Policy-Report-Only头和Content-Security-Policy头在同一个响应中返回,两种策略都生效。Content-Security-Policy标头中指定的策略被强制执行,而Content-Security-Policy-Report-Only策略仅生成报告,但不强制执行。

开启报告

默认情况下,违规报告不会被发送。为了开启违规报告,你需要声明report-uri策略指令,提供一个URI去接收传送报告:

Content-Security-Policy: default-src 'self'; report-uri http://reportcollector.example.com/collector.cgi

当你需要设置服务器去接收报告的时候,服务器可以按照您认为合适的任何方式存储或者处理它们。

违规报告语法

违规报告JSON对象包含以下数据:

  • blocked-uri
    通过内容安全策略加载时被阻止的资源URI。如果被阻塞的URI来自一个不同的源而不是document-uri的时候,被阻塞的URI被截断为协议,主机和端口。
  • disposition
    无论是"enforce"或者"report",都依赖于Content-Security-Policy-Report-Only或者Content-Security-Policy头。
  • document-uri
    违规发生地方的文档url
  • effective-directive
    强制执行导致违规的指令。
  • original-policy
    Content-Security-Policy HTTP头设置的原始策略。
  • referrer
    发生违规的文档的referrer。
  • script-sample
    行内脚本,事件处理器,或者样式的前40行
  • status-code
    实例化全局对象资源的http状态码
  • violated-directive
    违反的策略部分的名称

违规报告采样

http://example.com/signup.html仅支持从cdn.example.com下载样式表

Content-Security-Policy: default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports
<!DOCTYPE html>
<html>
  <head>
    <title>Sign Up</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    ... Content ...
  </body>
</html>
{
  "csp-report": {
    "document-uri": "http://example.com/signup.html",
    "referrer": "",
    "blocked-uri": "http://example.com/css/style.css",
    "violated-directive": "style-src cdn.example.com",
    "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports"
  }
}

CSP指令指南

Content Security Policy请求头由一个或者多个指令组成,多个指令的话由冒号”;“分隔

default-src

default-src指令定义了加载资源(js,图片,css,字体,ajax请求,frame,h5资源)的默认策略。
不是所有指令都回退到default-src

default-src 'self' cdn.example.com;

script-src

定义js资源的有效路径。

script-src 'self' js.example.com;

style-src

定义css资源的有效路径。

style-src 'self' css.example.com;

img-src

定义图片资源的有效路径。

img-src 'self' img.example.com;

connect-src

应用与XMLHttpRequest(AJAX),WebSocket,fetch(),<a ping>或EventSource。如果不允许会返回一个400状态码。

connect-src 'self';

font-src

定义字体的有效路径(通过@font-face加载)

font-src font.example.com;

object-src

定义插件的资源,例如<object><embed><applet>

object-src 'self';

media-src

定义音频和视频的有效资源,例如HTML5的<audio><video>

media-src media.example.com;

frame-src

定义可加载frame的资源。在CSP2.0中,不推荐frame-src,推荐child-src。CSP3.0也推荐使用child-src。

frame-src 'self';

sandbox

类似于frame sandbox属性。

sandbox allow-forms allow-scripts;

report-uri

CSP失败情况下报告的URI。CSP3.0推荐使用report-to指令。

report-uri /some-report-uri;

child-src

定义web worker和嵌入的浏览器上下文(例如frame,iframe)的资源

child-src 'self'

form-action

定义了HTML<form>action的有效资源

form-action 'self'

frame-ancestors

<frame> <iframe> <object> <embed> <applet>嵌入的资源。如果将这个设置为'none',等价于X-Frame-Options: DENY

frame-ancestors 'none';

plugin-types

定义插件的MIME type。

plugin-types application/pdf

base-uri

定义HTML的src白名单。

base-uri 'self';

report-to

report-to groupName;

worker-src

限制Worker,SharedWorker,ServiceWorker的URL。

worker-src 'none';

manifest-src

manifest-src 'none';

prefetch-src

prefetch和prerender的请求

prefetch-src 'none'

navigate-to

navigate-to example.com

腾讯AlloyTeam两篇非常好的CSP文章

XSS终结者-CSP理论与实践
《Csp Nonce – 守护你的 inline Script》

参考文章:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
https://content-security-policy.com/