内容安全策略

什么是 CSP?

内容安全策略 (CSP) 是一种额外的安全层,有助于检测和缓解某些类型的攻击,包括跨站点脚本 (XSS) 和数据注入攻击。这些攻击被用于从数据窃取到网站篡改,再到恶意软件分发等各种目的。

集成步骤

添加路由插件

要将中间件插件添加到您的应用程序,只需在路由文件夹中添加一个名为 [email protected] 的文件。此文件将在每次请求时加载,允许您添加标头、修改响应等等。

添加插件
src/
└── routes/
    ├── [email protected]         # The plugin which runs on every request (route middleware)
    ├── contact/
       └── index.mdx         # https://example.com/contact
    ├── about/
       └── index.md          # https://example.com/about
    ├── index.mdx             # https://example.com/
    
    └── layout.tsx            # This layout is used for all pages

示例

此模板提供了非常宽松的向后兼容默认值。强烈建议您根据您的具体用例对其进行自定义。由于这是一个高级主题,您应该仔细查看 MDNweb.dev 以更好地了解 CSP。请注意,在开发模式下,Vite 脚本没有 nonce 并且会报告。因此,此示例在开发模式下不会添加 csp。

import type { RequestHandler } from "@builder.io/qwik-city";
import { isDev } from "@builder.io/qwik/build";
 
export const onRequest: RequestHandler = event => {
  if (isDev) return; // Will not return CSP headers in dev mode
  const nonce = Date.now().toString(36); // Your custom nonce logic here
  event.sharedMap.set("@nonce", nonce);
  const csp = [
    `default-src 'self' 'unsafe-inline'`,
    `font-src 'self'`,
    `img-src 'self' 'unsafe-inline' data:`,
    `script-src 'self' 'unsafe-inline' https: 'nonce-${nonce}' 'strict-dynamic'`,
    `style-src 'self' 'unsafe-inline'`,
    `frame-src 'self' 'nonce-${nonce}'`,
    `object-src 'none'`,
    `base-uri 'self'`,
  ];
 
  event.headers.set("Content-Security-Policy", csp.join("; "));
};

也将其添加到服务工作者中

src/root.ts
import { component$, useServerData } from "@builder.io/qwik";
import {
  QwikCityProvider,
  RouterOutlet,
  ServiceWorkerRegister,
} from "@builder.io/qwik-city";
import { RouterHead } from "./components/router-head/router-head";
import { isDev } from "@builder.io/qwik/build";
 
import "./global.css";
 
export default component$(() => {
  const nonce = useServerData<string | undefined>("nonce");
  return (
    <QwikCityProvider>
      <head>
        <meta charSet="utf-8" />
        {!isDev && <link rel="manifest" href={`${import.meta.env.BASE_URL}manifest.json`} />}
 
        <RouterHead />
      </head>
      <body lang="en">
        <RouterOutlet />
        {!isDev && <ServiceWorkerRegister nonce={nonce} />}
      </body>
    </QwikCityProvider>
  );
});

自定义脚本

如果您需要添加 nonce 的自定义脚本标签,可以使用 useServerData 钩子从服务器获取 nonce 并将其添加到您的脚本标签中。

src/components/some-component.tsx
export default component$(() => {
  const nonce = useServerData<string | undefined>("nonce");
  return (
    <div>
      <script nonce={nonce}>alert("Hello world")</script>
    </div>
  );
});

验证您的 CSP

有一个很棒的工具可以验证您的 CSP:https://csp-evaluator.withgoogle.com/

贡献者

感谢所有帮助改进本文档的贡献者!

  • tzdesign
  • jordanw66
  • mrhoodz
  • the-zimmermann
  • hamatoyogi