Web 开发人员需要了解的内容安全策略 (CSP)





0/5 (0投票)
本文讨论了 Web 开发人员需要了解的内容安全策略。
引言
内容安全策略 (CSP) 是万维网联盟 (W3C) 推出的一项计算机安全标准,用于防止跨站脚本 (XSS) 和点击劫持攻击。简单来说,CSP 是一个允许在网页上加载或执行的内容来源的白名单。我们将探讨 CSP 的三个版本以及每个版本的相关功能,但需要注意的是,CSP Level 3 尚未被批准为 W3C 推荐标准,目前仍是正在进行的草案。在标准化之前,它仍可能随时发生变化。在接下来的内容中,我们会指出这些版本之间的区别。
什么是跨站脚本?
跨站脚本 (XSS) 攻击是一种代码注入类型,其中恶意脚本被注入到受信任的网站中。一个很好的例子可能发生在电子商务网站上:一个买家发布了一个带有恶意代码的产品评论,该代码被保存在服务器上。对于每个查看该产品评论的客户,都会执行恶意代码。
CSP 的实际应用
CSP 可以在 HTTP 响应头中指定。当 Web 客户端(如 Web 浏览器)从 Web 服务器请求资源时,它会发送一个 HTTP 请求,并在请求头中包含服务器的许多信息。如果请求成功,Web 服务器会回复该资源,并在响应头中告知 Web 浏览器如何处理响应。在 CSP 的情况下,它指定了从哪里获取网页内容的受信任来源。在支持 CSP 2 的浏览器中,我们还可以选择在 HTML meta 标签中指定 CSP。在我们的示例中,我们将使用这种方式;我们采取一种与 Web 框架无关的方法来保持简单。您只需要一个文本编辑器和现代 Web 浏览器即可遵循这些示例。
CSP 的结构
CSP 以 `Content-Security-Policy` 文本开头,后面跟着一个或多个指令。每个指令以分号结束,分号可以作为下一个指令的开始。每个指令可以有零个或多个值。值之间用空格分隔。通常,值只是一个受信任的来源 URI。
Content-Security-Policy [directive] <value>;
这是一个单指令 CSP 的示例。`default-src` 指令和 '`self`' 值指示 Web 浏览器仅信任来自与网页相同来源的内容。
Content-Security-Policy default-src 'self';
下面显示了 `meta` 标签中等效的 CSP。
<meta http-equiv="Content-Security-Policy" content="default-src 'self';>
请注意,`meta` 标签必须在 HTML 的 `head` 部分指定,而不是在 `body` 部分。开发人员必须注意的一个大缺点是:使用 `meta` 标签方法时,CSP 规则要到 `meta` 标签被读取和处理后才会生效。
这是在没有 CSP 的情况下从 CodeProject 加载图像的 HTML。您可以将代码复制并粘贴到一个空的 HTML 文件中,并将其本地保存。
<html>
<head>
<title>CSP
in Action</title>
<head>
<body>
<p><img
src="https://codeproject.org.cn/App_Themes/CodeProject/Img/logo250x135.gif"
/> </p>
</body>
</html>
通过双击文件管理器中的文件,在浏览器中查看 HTML,图像将从 CodeProject 下载并显示。
我们添加一个 CSP meta 标签。
<html>
<head>
<meta
http-equiv="Content-Security-Policy" content="default-src
'self';">
<title>CSP
in Action</title>
<head>
<body>
<p><img
src="https://codeproject.org.cn/App_Themes/CodeProject/Img/logo250x135.gif"
/> </p>
</body>
</html>
现在尝试在浏览器中查看页面。
砰!现在显示了损坏的图像,表明该图像未被获取,因为 www.codeproject.com 不是同一来源域。在 Web 浏览器中按 **F12** 打开开发者工具,然后导航到控制台选项卡。在 Chrome 中,它会以红色显示此错误。
拒绝加载图像“https://codeproject.org.cn/App_Themes/CodeProject/Img/logo250x135.gif”,因为它违反了以下内容安全策略指令:“default-src 'self'”。请注意,未显式设置 'img-src',因此 'default-src' 被用作后备。
如前所述,我们通过 `default-src` 指令有效地将所有内容限制为使用 '`self`' 关键字的同一来源。
让我们在 `default-src` 后面追加一个空格,然后是 CodeProject URI。为简单起见,我只显示更新的 `meta` 标签,其余 HTML 保持不变。
<meta http-equiv="Content-Security-Policy" content="default-src 'self'
https://codeproject.org.cn;">
再次查看页面。现在显示了 CodeProject 图像。注意:`self` 关键字必须用单引号括起来,而 URI 则不需要。
在浏览器中查看页面。现在图像回来了。由于 gif 是图像资源,让我们进行一些重构,并将 CodeProject URI 放在 `img-src` 指令下。
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src
https://codeproject.org.cn;">
再次在浏览器中查看页面。图像仍然出现。在此之前,没有指定 `img-src`。那么它的值是多少?答案是,当未指定时,它从 `default-src` 继承。注意:如果您的 URI 重定向到另一个域上的 URI,则该域也必须在 CSP 中。
CSP 指令
CSP 指令主要涵盖可以指定来源的的内容类型。本文涵盖了大多数指令。所有回退到 `default-src` 的指令都显示在下面的层级结构中。
- `default-src`:当其他获取指令未明确指定时,它们的主要后备。
- `child-src`:列出使用 `` 和 `
- `script-src`:列出 JavaScript 的可信来源。
- `object-src`:列出 `
- `style-src`:列出样式表 (CSS) 的可信来源。
- `img-src`:列出图像和网站图标的受信任来源。
- `media-src`:列出使用 `
- `frame-src`:列出使用 `` 和 `
- `font-src`:列出使用 `@font-face` 加载的字体的受信任来源。
- `connect-src`:限制可以通过脚本接口加载的 URL。脚本接口包括 ``、Fetch、XMLHttpRequest、WebSocket 和 EventSource。
- `worker-src`:列出 Worker、SharedWorker 或 ServiceWorker 脚本的可信来源。
- `base-uri`:限制可在文档的 `
` 元素中使用的 URL。 - `plugin-types`:通过限制可以加载的资源类型来限制可以嵌入文档的插件集。例如,要允许 Flash,请在此指令中指定其 MIME 类型:`application/x-shockwave-flash`。
- `sandbox`:将资源置于类似于 `
- `form-action`:限制可用于从给定上下文提交表单的 URL。
- `frame-ancestors:`:限制可能使用 ``、`
- `report-uri`:列出 Web 浏览器报告内容安全策略违规的 URL。这些违规报告由通过 HTTP POST 请求发送到指定 URI 的 JSON 文档组成。在 CSP 3 中已弃用,但仍广泛支持。
- `report-to`:`report-uri`(上面提到)已重命名为 `report-to`,并且 `report-uri` 在 CSP 3 中已弃用。但是,在撰写本文时,没有任何浏览器支持 `report-to`。为 CSP 做好未来规划,可以同时指定 `report-uri` 和 `report-to`。
- `block-all-mixed-content`:禁止在通过 HTTPS 加载页面时使用 HTTP 加载任何资源。
- `upgrade-insecure-requests`:指示 Web 浏览器将站点上的所有不安全 URL(通过 HTTP 提供的 URL)视为已替换为安全 URL(通过 HTTPS 提供的 URL)。此指令适用于需要重写大量不安全旧版 URL 的网站。
- `require-sri-for`:要求页面上的外部脚本或样式使用子资源完整性 (SRI)。
CSP 值
每个指令后面都跟着一个或多个由空格分隔的值。可接受的值类型主要分为两类:关键字和 URI。
除通配符外,所有关键字都必须用单引号括起来。
- '`self`':将来源限制为同一来源。
- '`none`':不允许任何来源。
- `*`:通配符。
- '`unsafe-inline`':允许内联 JavaScript 代码和样式表。
- '`unsafe-eval`':允许通过 `eval()` 进行动态 JavaScript。
除了同一来源之外,指定外部受信任来源 URI 的一个非常常见的原因是需要支持从内容分发网络 (CDN) 加载资源,CDN 是一个地理上分布的代理服务器网络,用于存储常用下载的内容。
URI 不能用单引号括起来!
在 CSP 1 中,URI 只允许包含方案(http 或 https)、域和端口号。
https://example.com:80/
而在 CSP 2 中,则允许使用子域和路径。此 URI 允许 `js` 文件夹中的所有文件。
https://example.com:80/js/
此 URI 将 `js` 视为文件,而不是文件夹,因为它后面没有斜杠。
https://example.com:80/js
要允许所有子域,请使用星号作为通配符。
https://*. example.com:80/
结论
在本文中,我们已经看到 CSP 被用于限制资源来源,以消除运行/显示不受信任内容的可能性。需要提醒的是,开发人员必须极其谨慎,以确保网页所需的所有来源都不会被忽略或遗漏在 CSP 中,否则会导致功能中断,从而拒绝为用户提供服务。