在JSON数据接口中防御XSS攻击需要从输入过滤、输出编码、架构设计三个层面进行综合防护,以下是具体实现方案及最佳实践:
一、输入过滤与校验
1. 请求参数白名单过滤
- JSON Schema验证:定义严格的数据结构,限制字段类型和内容格式。 { "type": "object", "properties": { "username": { "type": "string", "pattern": "^[a-zA-Z0-9_]{3,20}$" }, "comment": { "type": "string", "maxLength": 500 } }, "required": ["username"] }
- Java实现(使用Everit JSON Schema库): JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); JsonSchema schema = factory.getSchema(schemaJson); ProcessingReport report = schema.validate(jsonNode); if (!report.isSuccess()) throw new ValidationException("Invalid input");
2. 危险字符转义
- 后端自动转义:在反序列化时对字符串字段进行HTML实体编码。 // Jackson自定义反序列化器 public class SafeStringDeserializer extends JsonDeserializer<String> { @Override public String deserialize(JsonParser p, DeserializationContext ctxt) { String raw = p.getValueAsString(); return StringEscapeUtils.escapeHtml4(raw); // 转义特殊字符 } } // 注册到ObjectMapper ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addDeserializer(String.class, new SafeStringDeserializer()); mapper.registerModule(module);
二、输出编码控制
1. 安全序列化配置
- 禁用自动转义:明确控制JSON生成时的转义策略。 // Jackson配置 ObjectMapper mapper = new ObjectMapper(); mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
- 前端安全渲染:强制使用textContent而非innerHTML插入数据。 // React安全渲染示例 const SafeDiv = ({ content }) => <div>{content}</div>; // 自动转义
2. 内容安全策略(CSP)
- HTTP头设置:限制脚本执行来源。 Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com
- Spring Security配置: @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) { http.headers() .contentSecurityPolicy("default-src 'self'; script-src 'self'"); return http.build(); }
三、架构级防护
1. 请求体深度过滤
- JSON树遍历过滤:解析JSON后递归处理所有字符串节点。 public JsonNode sanitizeJson(JsonNode node) { if (node.isTextual()) { return TextNode.valueOf(StringEscapeUtils.escapeHtml4(node.asText())); } else if (node.isObject()) { ObjectNode obj = (ObjectNode) node; obj.fields().forEachRemaining(entry -> obj.set(entry.getKey(), sanitizeJson(entry.getValue()))); return obj; } else if (node.isArray()) { ArrayNode arr = (ArrayNode) node; arr.forEach(this::sanitizeJson); return arr; } return node; }
2. DTO模式隔离
- 数据传输对象(DTO):隔离前端输入与领域模型。 public class UserRequestDTO { @NotBlank @Size(max = 50) private String username; @SafeHtml // 自定义注解触发过滤 private String bio; }
3. 安全框架集成
- Spring Security配置:全局启用XSS防护。 @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) { http.headers() .xssProtection() .and() .contentSecurityPolicy("script-src 'self'"); } }
四、典型攻击场景防御
场景1:JSON参数注入
- 问题:{"query": "<script>alert(1)</script>"}被直接嵌入SQL。
- 防御:
- 使用预编译语句(JPA/Hibernate): @Query("SELECT u FROM User u WHERE name = :name") List<User> findByName(@Param("name") String name);
- 输入过滤: String sanitizedQuery = StringEscapeUtils.escapeSql(userInput);
场景2:JSON响应XSS
- 问题:返回{"message": "<img src=x onerror=alert(1)>"}
- 防御:
- 强制转义响应内容: @Bean public MappingJackson2HttpMessageConverter customConverter() { ObjectMapper mapper = new ObjectMapper(); mapper.configure(JsonWriteFeature.ESCAPE_NON_ASCII.mappedFeature(), true); return new MappingJackson2HttpMessageConverter(mapper); }