JSON 安全考虑
JSON 安全概述
虽然 JSON 是一种相对安全的数据格式,但在实际使用中仍然存在多种安全风险。了解这些风险并采取适当的防护措施至关重要。
💉
JSON 注入
恶意数据注入到 JSON 中
高风险
⚠️ 重要提醒
永远不要信任来自客户端的 JSON 数据。所有来自外部源的 JSON 数据都应该经过严格的验证和清理。
JSON 注入攻击
风险描述
JSON 注入发生在攻击者能够将恶意内容注入到 JSON 数据结构中,可能导致数据泄露、代码执行或其他安全漏洞。
注入示例
String userInput = "恶意用户\"; alert('XSS'); //";
String json = "{\"name\": \"" + userInput + "\"}";
var data = eval('(' + json + ')');
防护措施
使用安全的 JSON 解析方法,永远不要使用 eval() 来解析 JSON。
try {
var data = JSON.parse(jsonString);
} catch (e) {
console.error('Invalid JSON');
}
public String sanitizeJsonInput(String input) {
return input
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("'", "\\'")
.replace("\n", "\\n")
.replace("\r", "\\r");
}
JSON 劫持 (JSON Hijacking)
风险描述
JSON 劫持是一种利用浏览器特性窃取 JSON 数据的攻击方式。攻击者通过重写 JavaScript 数组构造函数来窃取敏感数据。
攻击原理
var stolenData = [];
Array = function() {
stolenData = arguments;
};
var script = document.createElement('script');
script.src = 'https://api.example.com/sensitive-data';
document.body.appendChild(script);
防护措施
防止 JSON 劫持的最佳实践:
- 永远不要以数组形式返回敏感 JSON 数据
- 在 JSON 响应前添加前缀
- 使用 POST 请求而不是 GET 请求获取敏感数据
- 设置合适的 CORS 策略
[{"id": 1, "name": "张三", "email": "zhangsan@example.com"}]
while(1);[{"id": 1, "name": "张三", "email": "zhangsan@example.com"}]
fetch('/api/sensitive-data')
.then(response => response.text())
.then(text => {
const jsonString = text.replace('while(1);', '');
return JSON.parse(jsonString);
});
XXE 攻击 (XML External Entity)
风险描述
虽然 JSON 本身不支持外部实体,但某些 JSON 解析库可能支持从 JSON 到 XML 的转换,或者在处理包含 XML 数据的 JSON 时可能受到 XXE 攻击。
攻击示例
{
"xmlData": "<?xml version=\"1.0\"?>\n" +
"<!DOCTYPE foo [\n" +
"<!ELEMENT foo ANY >\n" +
"<!ENTITY xxe SYSTEM \"file:///etc/passwd\" >]>\n" +
"<foo>&xxe;</foo>"
}
防护措施
防止 XXE 攻击的最佳实践:
- 禁用 XML 外部实体处理
- 使用安全的 XML 解析器配置
- 验证和过滤输入数据
- 避免在 JSON 中直接嵌入 XML 数据
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);
from defusedxml import defused_etree as ET
tree = ET.parse(xml_string)
JSONP 安全考虑
风险描述
JSONP (JSON with Padding) 允许跨域请求,但存在严重的安全风险,包括:
- CSRF (跨站请求伪造) 攻击
- 数据泄露
- 恶意代码执行
JSONP 工作原理
function handleData(data) {
console.log(data);
}
var script = document.createElement('script');
script.src = 'https://api.example.com/data?callback=handleData';
document.head.appendChild(script);
handleData({"name": "张三", "age": 30});
防护措施
JSONP 安全最佳实践:
- 使用 CORS 替代 JSONP
- 验证回调函数名称
- 设置 Content-Type 为 application/javascript
- 实施 CSRF 保护
public String handleJsonpRequest(String callback) {
if (!callback.matches("^[a-zA-Z_$][0-9a-zA-Z_$]*$")) {
callback = "callback";
}
String data = "{\"name\": \"张三\", \"age\": 30}";
return callback + "(" + data + ");";
}
response.setHeader("Access-Control-Allow-Origin", "https://trusted-domain.com");
response.setHeader("Access-Control-Allow-Methods", "GET, POST");
response.setHeader("Access-Control-Allow-Headers", "Content-Type");
深度嵌套攻击
风险描述
攻击者可能发送深度嵌套的 JSON 对象,导致解析器消耗大量内存或引发栈溢出,从而造成拒绝服务 (DoS) 攻击。
攻击示例
{
"a": {
"b": {
"c": {
"d": {
}
}
}
}
}
防护措施
防止深度嵌套攻击:
- 设置最大解析深度限制
- 限制 JSON 数据大小
- 使用流式解析器处理大型数据
- 实施超时机制
function safeJsonParse(jsonString, maxDepth = 100) {
let depth = 0;
const reviver = function(key, value) {
if (typeof value === 'object' && value !== null) {
depth++;
if (depth > maxDepth) {
throw new Error('JSON too deeply nested');
}
}
return value;
};
return JSON.parse(jsonString, reviver);
}
JsonFactory factory = new JsonFactory();
factory.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
ObjectMapper mapper = new ObjectMapper(factory);
mapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
敏感数据泄露
风险描述
JSON 响应中可能意外包含敏感信息,如密码、API 密钥、内部系统信息等,这些信息可能被攻击者利用。
常见泄露场景
| 泄露类型 |
示例 |
风险等级 |
| 调试信息 |
{"debug": true, "internal_ip": "192.168.1.1"} |
中风险 |
| 完整错误信息 |
{"error": "SQL Syntax Error: SELECT * FROM users"} |
高风险 |
| 敏感字段 |
{"user": {"password": "plaintext", "ssn": "123-45-6789"}} |
高风险 |
| 内部标识符 |
{"user_id": 123, "api_key": "sk_live_..."} |
高风险 |
防护措施
防止敏感数据泄露:
- 实施数据脱敏和过滤
- 使用专门的 DTO (数据传输对象)
- 在生产环境禁用调试信息
- 记录和监控数据访问
public class UserDTO {
private Long id;
private String username;
private String email;
}
public class User {
private Long id;
private String username;
private String email;
@JsonIgnore
private String password;
@JsonIgnore
private String internalId;
}
public class SensitiveDataSerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {
String masked = value.substring(0, Math.min(2, value.length())) + "***";
gen.writeString(masked);
}
}
内容安全策略 (CSP)
防护措施
内容安全策略 (CSP) 可以帮助缓解多种 JSON 相关攻击,特别是 XSS 攻击。
CSP 配置示例
Content-Security-Policy: default-src 'self';
script-src 'self' 'unsafe-inline';
object-src 'none';
base-uri 'self';
connect-src 'self' https://api.example.com;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.contentSecurityPolicy("default-src 'self'; script-src 'self' 'unsafe-inline'; object-src 'none';");
}
}
add_header Content-Security-Policy "default-src 'self';";
CSP 指令说明
| 指令 |
作用 |
推荐值 |
default-src |
默认资源加载策略 |
'self' |
script-src |
控制 JavaScript 执行 |
'self' (避免 'unsafe-inline') |
connect-src |
控制 AJAX、WebSocket 连接 |
限制到可信域名 |
object-src |
控制 Flash、Java 等插件 |
'none' |
安全演示
在下面的演示中,您可以测试 JSON 安全验证功能。
JSON 安全清单
开发阶段
- 使用安全的 JSON 解析库
- 验证所有输入数据
- 实施适当的错误处理
- 避免在错误消息中泄露敏感信息
- 使用参数化查询防止注入
部署阶段
- 配置适当的内容安全策略 (CSP)
- 设置安全的 HTTP 头
- 实施速率限制
- 启用 HTTPS
- 配置适当的 CORS 策略
监控和维护
- 定期更新依赖库
- 监控异常请求模式
- 实施日志记录和审计
- 定期进行安全测试
- 建立安全事件响应计划
最佳实践对比
| 不安全做法 |
安全做法 |
说明 |
| 使用 eval() 解析 JSON |
使用 JSON.parse() |
eval() 会执行任意代码 |
| 信任所有客户端数据 |
验证和清理所有输入 |
客户端数据可能被篡改 |
| 返回完整错误信息 |
返回通用错误消息 |
防止信息泄露 |
| 使用 JSONP 跨域 |
使用 CORS |
CORS 更安全可控 |
| 无限制的 JSON 大小 |
设置大小和深度限制 |
防止 DoS 攻击 |