【CSP】内容安全策略违规报告接口示例

本文最后更新于:2025年2月18日 下午

CSP违规报告接口示例

Maven依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<!-- json解析 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.51</version>
</dependency>
<!-- 官方地址:https://hutool.cn/ -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
<!-- mysql驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

前端

(可以在服务器端设置此请求头)而不是<meta>标签

1
Content-Security-Policy: default-src 'self'; script-src 'self'; report-uri /csp-violation-report-endpoint

例如Spring后端项目:

1
2
3
4
5
6
7
@GetMapping()
public String index(HttpServletResponse response) {
// 设置CSP头
response.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self'; report-uri /csp-violation-report-endpoint");

return "index";
}

后端接收模型

CspViolationReportWrapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

/**
* 接收CSP请求携带的参数
* @author peter
* @date 2024/10/31
* @className CspViolationReportWrapper
*/
public class CspViolationReportWrapper {

@JsonProperty("csp-report")
private CspViolationReport cspReport;

public CspViolationReport getCspReport() {
return cspReport;
}

public void setCspReport(CspViolationReport cspReport) {
this.cspReport = cspReport;
}

@Data
public static class CspViolationReport {
private String referrer;

@JsonProperty("status-code")
private int statusCode;

private String disposition;
private String scriptSample;

@JsonProperty("violated-directive")
private String violatedDirective;

@JsonProperty("original-policy")
private String originalPolicy;

@JsonProperty("source-file")
private String sourceFile;

@JsonProperty("document-uri")
private String documentUri;

@JsonProperty("line-number")
private int lineNumber;

@JsonProperty("effective-directive")
private String effectiveDirective;

@JsonProperty("blocked-uri")
private String blockedUri;

}
}

实体类

CspViolationReport.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import lombok.Data;

/**
* 内容安全策略违规报告模型
* @author peter
* @date 2024/10/31
* @description TODO
*/
@Data
public class CspViolationReport {

/**
* 唯一标识。
*/
private Long id;

/**
* 违规发生的文档URI。
*/
private String documentUri;

/**
* 发送请求的来源。
*/
private String referrer;

/**
* 触发违规的CSP指令。
*/
private String violatedDirective;

/**
* 当前生效的CSP指令。
*/
private String effectiveDirective;

/**
* 引发违规的资源文件。
*/
private String sourceFile;

/**
* 违规发生的行号。
*/
private int lineNumber;

/**
* 违规发生的列号。
*/
private int columnNumber;

/**
* 违规请求的HTTP状态码。
*/
private String statusCode;

/**
* 自定义时间戳
*/
private Long timestamp;
}

转换器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.msrl.zhibo.thirdparty.demo;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

@Component
public class CspReportMessageConverter extends MappingJackson2HttpMessageConverter {

public CspReportMessageConverter(ObjectMapper objectMapper) {
super(objectMapper);
// 这里可以添加自定义的媒体类型
setSupportedMediaTypes(Collections.singletonList(MediaType.valueOf("application/csp-report")));
}
}

配置类

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {

// 添加转换器
private final CspReportMessageConverter cspReportMessageConverter;

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(cspReportMessageConverter);
}
}

控制层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
* 内容安全策略违规报告接口
* @author peter
* @date 2024/10/31
* @description TODO
*/
@RestController
@RequestMapping("/csp-violation-report-endpoint")
public class CspReportController {

@PostMapping(consumes = "application/csp-report")
public ResponseEntity<Void> receiveCspReport(@RequestBody CspViolationReportWrapper cspViolationReportWrapper) {

CspViolationReportWrapper.CspViolationReport cspReport = cspViolationReportWrapper.getCspReport();
CspViolationReport cspViolationReport = BeanUtil.copyProperties(cspReport, CspViolationReport.class);

cspViolationReport.setTimestamp(System.currentTimeMillis());
// 处理CSP违规报告,例如保存到数据库、记录日志等
System.out.println("CSP Violation Report: " + cspViolationReport);

// TODO: 将报告存储到数据库

// 返回204 No Content表示接收成功
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
}


【CSP】内容安全策略违规报告接口示例
https://superlovelace.top/2024/10/31/CSP违规报告接口示例/
作者
棱境
发布于
2024年10月31日
更新于
2025年2月18日
许可协议