Java应用中的内容安全策略(CSP):防范XSS与数据注入的实践

Java 应用中的内容安全策略(CSP):防范 XSS 与数据注入的实践

大家好,今天我们来深入探讨一个对于现代 Web 应用安全至关重要的主题:内容安全策略(CSP)。特别是在 Java 应用环境中,有效地实施 CSP 可以显著降低跨站脚本攻击(XSS)和数据注入等安全风险。本次讲座将从 CSP 的基本概念出发,逐步深入到如何在 Java 应用中实现和优化 CSP,并提供实际的代码示例。

1. 内容安全策略(CSP)概述

内容安全策略(CSP)是一种基于 HTTP 响应头的安全策略机制,它允许服务器管理者明确声明浏览器可以加载哪些来源的内容。 通过定义可信的内容来源,CSP 可以有效地减少 XSS 攻击的风险。 简单来说,CSP 就像一道防火墙,控制着浏览器可以执行哪些外部资源,从而阻止恶意脚本的执行。

传统上,防御 XSS 依赖于输入验证和输出编码。 虽然这些技术很重要,但它们并不能完全消除 XSS 风险。CSP 提供了一种额外的、防御纵深的安全层,即使攻击者成功注入了恶意脚本,CSP 也能阻止浏览器执行它。

CSP 的核心思想:显式地声明允许加载的内容来源,而不是默认允许所有来源。

2. CSP 指令详解

CSP 通过一系列指令来定义允许加载的内容来源。 这些指令放在 HTTP 响应头的 Content-Security-Policy 字段中。 常见的 CSP 指令包括:

指令 描述 示例
default-src 定义所有其他资源类型(例如 script-srcstyle-srcimg-src)的默认源。如果未指定特定资源类型的指令,则使用 default-src default-src 'self'
script-src 定义 JavaScript 脚本的有效源。 script-src 'self' https://cdn.example.com
style-src 定义 CSS 样式的有效源。 style-src 'self' https://fonts.googleapis.com
img-src 定义图像的有效源。 img-src 'self' data:
connect-src 定义可以进行网络请求的有效源(例如,通过 XMLHttpRequestFetch APIWebSocket)。 connect-src 'self' wss://example.com
font-src 定义字体文件的有效源。 font-src 'self' https://fonts.gstatic.com
media-src 定义媒体文件(例如,音频、视频)的有效源。 media-src 'self'
object-src 定义 <object><embed><applet> 元素的有效源。 object-src 'none'
frame-src 定义 <frame><iframe> 元素的有效源。 frame-src 'self' https://www.youtube.com
base-uri 定义可以使用的 <base> 元素的 URL。 base-uri 'self'
form-action 定义表单可以提交到的有效 URL。 form-action 'self'
upgrade-insecure-requests 指示浏览器自动将 HTTP URL 升级为 HTTPS URL。 upgrade-insecure-requests
block-all-mixed-content 阻止浏览器加载任何通过 HTTP 提供的资源,即使页面是通过 HTTPS 加载的。 block-all-mixed-content
report-uri 指定一个 URL,浏览器会将违反 CSP 策略的报告发送到该 URL。已过时,建议使用 report-to report-uri /csp-report
report-to 指定一个或多个端点,浏览器会将违反 CSP 策略的报告发送到这些端点。需要配合 Reporting-Endpoints HTTP 响应头使用。 report-to csp-endpoint
worker-src 定义 Worker 脚本的有效源。 worker-src 'self'
manifest-src 定义应用清单文件的有效源。 manifest-src 'self'
prefetch-src 定义预取资源的有效源。 prefetch-src 'self'

除了源列表,CSP 指令还可以使用以下关键字:

  • 'self':表示与文档来源相同的来源(协议、域名和端口)。
  • 'none':表示不允许加载任何资源。
  • 'unsafe-inline':允许使用内联 JavaScript 和 CSS。 强烈不建议使用,因为它会降低 CSP 的安全性。
  • 'unsafe-eval':允许使用 eval() 等动态代码执行函数。 强烈不建议使用,因为它会降低 CSP 的安全性。
  • 'strict-dynamic':指定信任由当前页面安全地加载的脚本所加载的脚本。 与 nonce 或 hash 一起使用。
  • 'unsafe-hashes':允许启用特定的内联事件处理程序。
  • 'report-sample':指示浏览器在 CSP 报告中包含违规代码的示例。
  • 'nonce-<base64-value>':指定一个一次性使用的加密随机数,只有具有匹配 nonce 属性的脚本或样式才会被执行。
  • 'sha256-<base64-hash>''sha384-<base64-hash>''sha512-<base64-hash>':指定脚本或样式的 SHA 哈希值,只有具有匹配哈希值的脚本或样式才会被执行。

3. 在 Java 应用中实现 CSP

在 Java 应用中,可以通过多种方式来设置 CSP 响应头。 常用的方法包括:

  • Servlet 过滤器 (Filter): 编写一个 Servlet 过滤器,拦截所有请求,并根据需要设置 Content-Security-Policy 响应头。
  • Spring Security: 使用 Spring Security 的 CSP 支持来配置 CSP 策略。
  • Web 服务器配置: 在 Web 服务器(例如,Tomcat、Jetty)的配置文件中设置 CSP 响应头。

3.1 使用 Servlet 过滤器实现 CSP

Servlet 过滤器是一种拦截 HTTP 请求和响应的组件,可以用来修改请求和响应头。 下面是一个使用 Servlet 过滤器设置 CSP 响应头的示例:

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;

@WebFilter("/*") // 拦截所有请求
public class CSPFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化操作,例如读取配置文件
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 设置 CSP 策略
        httpResponse.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self';");

        // 继续请求处理
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // 销毁操作,例如释放资源
    }
}

代码解释:

  1. @WebFilter("/*") 注解表示该过滤器拦截所有请求。
  2. doFilter 方法是过滤器的核心方法,它接收请求和响应对象,以及一个 FilterChain 对象。
  3. httpResponse.setHeader("Content-Security-Policy", ...) 设置 Content-Security-Policy 响应头,定义 CSP 策略。 在这个例子中,我们允许从同源加载所有资源,允许内联脚本和样式,允许加载 data: 协议的图像,允许从同源进行网络连接。

注意事项:

  • 'unsafe-inline' 的使用是为了简化示例,在实际生产环境中,强烈建议避免使用 'unsafe-inline',而是使用 nonce 或 hash 来允许内联脚本和样式。
  • 根据你的应用需求,自定义 CSP 策略。
  • 将该过滤器部署到你的 Java Web 应用中。

3.2 使用 Spring Security 实现 CSP

Spring Security 提供了一个方便的方式来配置 CSP 策略。 下面是一个使用 Spring Security 配置 CSP 的示例:

首先,确保你的项目中包含了 Spring Security 的依赖。 在 pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

然后,创建一个 Spring Security 配置类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.header.writers.StaticHeadersWriter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .headers()
                .addHeaderWriter(new StaticHeadersWriter("Content-Security-Policy",
                    "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self';"))
                .frameOptions().sameOrigin() // 允许同源的 iframe
                .and()
            .authorizeHttpRequests()
                .anyRequest().permitAll() // 允许所有请求
                .and()
            .csrf().disable(); // 禁用 CSRF,仅用于演示目的,生产环境需要启用 CSRF

        return http.build();
    }
}

代码解释:

  1. @Configuration@EnableWebSecurity 注解表示这是一个 Spring Security 配置类。
  2. filterChain 方法配置 Spring Security 的过滤器链。
  3. http.headers().addHeaderWriter(...) 添加一个 StaticHeadersWriter,用于设置 Content-Security-Policy 响应头。
  4. frameOptions().sameOrigin() 允许同源的 iframe 元素。
  5. authorizeHttpRequests().anyRequest().permitAll() 允许所有请求,在实际应用中,你需要根据你的安全需求配置更严格的授权规则。
  6. csrf().disable() 禁用 CSRF 保护,仅用于演示目的,在实际生产环境中,强烈建议启用 CSRF 保护。

注意事项:

  • 'unsafe-inline' 的使用是为了简化示例,在实际生产环境中,强烈建议避免使用 'unsafe-inline',而是使用 nonce 或 hash 来允许内联脚本和样式。
  • 根据你的应用需求,自定义 CSP 策略。
  • 根据你的安全需求,配置更严格的授权规则。
  • 在生产环境中,启用 CSRF 保护。

3.3 使用 Web 服务器配置实现 CSP

你也可以直接在 Web 服务器的配置文件中设置 CSP 响应头。 这种方法的优点是不需要修改应用程序代码,但缺点是需要在每个 Web 服务器上单独配置。

Tomcat 配置示例:

conf/web.xml 文件中添加以下配置:

<filter>
    <filter-name>CSPFilter</filter-name>
    <filter-class>org.apache.catalina.filters.HeaderFilter</filter-class>
    <init-param>
        <param-name>Content-Security-Policy</param-name>
        <param-value>default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self';</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CSPFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Jetty 配置示例:

jetty.xml 文件中添加以下配置:

<Set name="handler">
  <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerList">
    <Set name="handlers">
      <Array type="org.eclipse.jetty.server.Handler">
        <Item>
          <New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
        </Item>
        <Item>
          <New class="org.eclipse.jetty.server.handler.DefaultHandler"/>
        </Item>
        <Item>
          <New class="org.eclipse.jetty.server.handler.RequestLogHandler"/>
        </Item>
        <Item>
          <New class="org.eclipse.jetty.server.handler.ContextHandler">
            <Set name="contextPath">/</Set>
            <Set name="handler">
              <New class="org.eclipse.jetty.server.handler.ResourceHandler">
                <Set name="resourceBase">./src/main/webapp</Set>
              </New>
            </Set>
          </New>
        </Item>
        <Item>
          <New class="org.eclipse.jetty.server.handler.HeaderHandler">
            <Set name="responseHeaders">
              <Array type="java.lang.String">
                <Item>Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self';</Item>
              </Array>
            </Set>
          </New>
        </Item>
      </Array>
    </Set>
  </New>
</Set>

注意事项:

  • 'unsafe-inline' 的使用是为了简化示例,在实际生产环境中,强烈建议避免使用 'unsafe-inline',而是使用 nonce 或 hash 来允许内联脚本和样式。
  • 根据你的应用需求,自定义 CSP 策略。
  • 不同的 Web 服务器有不同的配置方式,请参考相应的文档。

4. 使用 Nonce 和 Hash 强化 CSP

为了避免使用 'unsafe-inline',我们可以使用 nonce 或 hash 来允许特定的内联脚本和样式。

4.1 使用 Nonce

Nonce 是一个一次性使用的加密随机数。 服务器在生成 HTML 页面时生成一个 nonce,并将其添加到 CSP 策略中。 然后,将相同的 nonce 添加到内联脚本和样式的 nonce 属性中。 只有具有匹配 nonce 的脚本和样式才会被执行。

Java 代码示例:

import java.security.SecureRandom;
import java.util.Base64;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;

@WebFilter("/*")
public class CSPNonceFilter implements Filter {

    private static final SecureRandom secureRandom = new SecureRandom(); // 安全的随机数生成器
    private static final Base64.Encoder base64Encoder = Base64.getEncoder(); // Base64 编码器

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 生成随机 nonce
        byte[] nonceBytes = new byte[16];
        secureRandom.nextBytes(nonceBytes);
        String nonce = base64Encoder.encodeToString(nonceBytes);

        // 设置 CSP 策略,包含 nonce
        httpResponse.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self' 'nonce-" + nonce + "'; style-src 'self' 'nonce-" + nonce + "'; img-src 'self' data:; font-src 'self'; connect-src 'self';");

        // 将 nonce 添加到请求属性中,以便在 JSP 页面中使用
        request.setAttribute("cspNonce", nonce);

        // 继续请求处理
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }
}

JSP 页面示例:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>CSP with Nonce Example</title>
</head>
<body>
    <h1>CSP with Nonce Example</h1>

    <script nonce="${cspNonce}">
        console.log("This script is allowed because it has the correct nonce.");
    </script>

    <style nonce="${cspNonce}">
        body {
            background-color: lightblue;
        }
    </style>

    <p>This is some content.</p>
</body>
</html>

代码解释:

  1. CSPNonceFilter 生成一个随机 nonce,并将其添加到 Content-Security-Policy 响应头中。
  2. CSPNonceFilter 将 nonce 添加到请求属性中,以便在 JSP 页面中使用。
  3. JSP 页面使用 ${cspNonce} 表达式获取 nonce,并将其添加到 <script><style> 元素的 nonce 属性中。

4.2 使用 Hash

Hash 是脚本或样式的 SHA 哈希值。 服务器计算脚本或样式的哈希值,并将其添加到 CSP 策略中。 只有具有匹配哈希值的脚本和样式才会被执行。

Java 代码示例:

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;

@WebFilter("/*")
public class CSPHashFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 内联 JavaScript 代码
        String inlineScript = "console.log("This script is allowed because it has the correct hash.");";

        // 计算 SHA-256 哈希值
        String scriptHash = calculateSha256Hash(inlineScript);

        // 内联 CSS 代码
        String inlineStyle = "body { background-color: lightblue; }";

        // 计算 SHA-256 哈希值
        String styleHash = calculateSha256Hash(inlineStyle);

        // 设置 CSP 策略,包含 hash
        httpResponse.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self' 'sha256-" + scriptHash + "'; style-src 'self' 'sha256-" + styleHash + "'; img-src 'self' data:; font-src 'self'; connect-src 'self';");

        // 将内联脚本和样式添加到请求属性中,以便在 JSP 页面中使用
        request.setAttribute("inlineScript", inlineScript);
        request.setAttribute("inlineStyle", inlineStyle);

        // 继续请求处理
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }

    // 计算 SHA-256 哈希值
    private String calculateSha256Hash(String data) throws IOException {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(data.getBytes("UTF-8"));
            return Base64.getEncoder().encodeToString(hash);
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            throw new IOException("Failed to calculate SHA-256 hash", e);
        }
    }
}

JSP 页面示例:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>CSP with Hash Example</title>
</head>
<body>
    <h1>CSP with Hash Example</h1>

    <script>
        ${inlineScript}
    </script>

    <style>
        ${inlineStyle}
    </style>

    <p>This is some content.</p>
</body>
</html>

代码解释:

  1. CSPHashFilter 计算内联脚本和样式的 SHA-256 哈希值,并将其添加到 Content-Security-Policy 响应头中。
  2. CSPHashFilter 将内联脚本和样式添加到请求属性中,以便在 JSP 页面中使用。
  3. JSP 页面使用 ${inlineScript}${inlineStyle} 表达式获取内联脚本和样式。

注意事项:

  • 每次修改内联脚本或样式时,都需要重新计算哈希值。
  • 可以使用不同的哈希算法,例如 SHA-384 或 SHA-512。

5. CSP 报告

CSP 报告允许你了解 CSP 策略是否阻止了某些资源的加载。 当浏览器检测到违反 CSP 策略时,它会向指定的 URL 发送一个报告。

配置 CSP 报告:

Content-Security-Policy 响应头中使用 report-to 指令来指定报告端点。 你还需要配置 Reporting-Endpoints HTTP 响应头来定义报告端点。

Java 代码示例:

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;

@WebFilter("/*")
public class CSPReportFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 设置 Reporting-Endpoints 响应头
        httpResponse.setHeader("Reporting-Endpoints", "csp-endpoint="/csp-report"");

        // 设置 CSP 策略,包含 report-to 指令
        httpResponse.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; report-to csp-endpoint;");

        // 继续请求处理
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }
}

Java 代码示例 (处理报告):

import java.io.IOException;
import java.io.BufferedReader;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/csp-report")
public class CSPReportServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 读取报告内容
        StringBuilder sb = new StringBuilder();
        try (BufferedReader reader = request.getReader()) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        }

        // 打印报告内容
        System.out.println("CSP Report: " + sb.toString());

        // TODO: 将报告内容记录到日志或数据库中
    }
}

代码解释:

  1. CSPReportFilter 设置 Reporting-EndpointsContent-Security-Policy 响应头。
  2. CSPReportServlet 接收 CSP 报告,并将其打印到控制台。

注意事项:

  • report-toreport-uri 的替代方案,report-uri 已过时。
  • 你需要在你的应用中配置一个端点来接收 CSP 报告。
  • CSP 报告包含有关违规的信息,例如违规的 URL、违规的指令和文档的 URL。

6. CSP 的部署和测试

在部署 CSP 策略之前,建议先在报告模式下测试它。 在报告模式下,CSP 策略不会阻止任何资源的加载,但会向指定的 URL 发送报告。 这可以帮助你了解 CSP 策略是否会阻止任何合法的资源,并根据需要进行调整。

启用报告模式:

Content-Security-Policy 响应头中使用 Content-Security-Policy-Report-Only 字段来启用报告模式。

Java 代码示例:

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;

@WebFilter("/*")
public class CSPReportOnlyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 设置 Reporting-Endpoints 响应头
        httpResponse.setHeader("Reporting-Endpoints", "csp-endpoint="/csp-report"");

        // 设置 CSP 策略,启用报告模式
        httpResponse.setHeader("Content-Security-Policy-Report-Only", "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; report-to csp-endpoint;");

        // 继续请求处理
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }
}

注意事项:

  • 在报告模式下,浏览器不会阻止任何资源的加载,但会向指定的 URL 发送报告。
  • 在部署 CSP 策略之前,务必在报告模式下进行充分的测试。

7. 最佳实践

  • 从严格的策略开始,逐步放宽。
  • 避免使用 'unsafe-inline''unsafe-eval'
  • 使用 nonce 或 hash 来允许内联脚本和样式。
  • 配置 CSP 报告,并定期查看报告。
  • 在部署 CSP 策略之前,先在报告模式下测试它。
  • 定期审查和更新 CSP 策略。
  • 结合其他安全措施,例如输入验证和输出编码,来提高 Web 应用的安全性。

总结:使用 CSP 保护你的 Java 应用

内容安全策略(CSP)是防御 XSS 攻击和数据注入的重要手段。 通过声明允许加载的内容来源,CSP 可以有效地减少攻击者利用漏洞的机会。 在 Java 应用中,可以使用 Servlet 过滤器、Spring Security 或 Web 服务器配置来实现 CSP。 为了提高 CSP 的安全性,建议使用 nonce 或 hash 来允许内联脚本和样式。 此外,配置 CSP 报告可以帮助你了解 CSP 策略是否阻止了某些资源的加载,并根据需要进行调整。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注