随着互联网应用的快速发展,API安全已成为系统架构中的重要环节。本文将详细介绍两种核心的安全防护机制:签名验证(防篡改)和数据加密(防泄露),帮助开发者构建更安全的API服务。
一、签名验证:防止请求被篡改
1.1 设计思路
对外提供的接口必须进行签名认证,确保请求在传输过程中未被恶意修改。采用统一的签名算法:
"时间戳 + 随机串 + 业务参数" → 排序 → 拼接APP_SECRET → SHA256加密
这种设计保证了前后端、第三方系统采用相同的验证标准,避免因实现差异导致的安全漏洞。
1.2 核心实现
java
public class SignUtil {
/**
* 生成签名
* @param map 除 sign 外的所有参数
* @param secret 分配给你的私钥
*/
public static String sign(Map<String, String> map, String secret) {
// 1. 参数名升序排列
Map<String, String> tree = new TreeMap<>(map);
tree.put("timestamp", String.valueOf(System.currentTimeMillis()));
// 2. 拼成 k=v&k=v
String join = tree.entrySet().stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("&"));
// 3. 最后拼密钥
String raw = join + "&key=" + secret;
// 4. SHA256
return DigestUtils.sha256Hex(raw).toUpperCase();
}
/** 验签:直接比对即可 */
public static boolean verify(Map<String, String> map, String secret, String requestSign) {
return sign(map, secret).equals(requestSign);
}
}
1.3 拦截器统一处理
java
@Component
public class SignInterceptor implements HandlerInterceptor {
@Value("${sign.secret.info}")
private String secret;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 只拦截接口
if (!(handler instanceof HandlerMethod)) return true;
Map<String, String> params = Maps.newHashMap();
request.getParameterMap().forEach((k, v) -> params.put(k, v[0]));
String sign = params.remove("sign"); // 签名不参与计算
if (!SignUtil.verify(params, secret, sign)) {
throw new BizException("签名错误");
}
return true;
}
}
二、数据加密:防止敏感信息泄露
2.1 设计原则
- AES对称加密:性能优秀,适合大量数据加密
- 密钥管理:集中存储在配置中心,支持动态更新
- 灵活控制:支持一键开关,不影响正常业务流程
- 精准加密:仅对敏感字段加密,避免全包加密影响调试效率
2.2 AES加密实现
java
public class AesUtil {
private static final String ALG = "AES/CBC/PKCS5Padding";
// 16 位密钥,生产环境应从配置中心获取
private static final String KEY = "12334523490abcdef";
private static final String IV = "abcdef1234567890123";
public static String encrypt(String src) {
try {
Cipher cipher = Cipher.getInstance(ALG);
SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
return Base64.getEncoder().encodeToString(cipher.doFinal(src.getBytes()));
} catch (Exception e) {
throw new RuntimeException("加密失败", e);
}
}
public static String decrypt(String src) {
try {
Cipher cipher = Cipher.getInstance(ALG);
SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
return new String(cipher.doFinal(Base64.getDecoder().decode(src)));
} catch (Exception e) {
throw new RuntimeException("解密失败", e);
}
}
}
三、安全实践建议
3.1 签名验证优化
- 时间戳校验:限制请求时间窗口,防止重放攻击
- 随机串防重放:记录已使用的随机串,避免重复请求
- 参数完整性:确保所有必要参数都参与签名计算
3.2 加密策略
- 分级加密:根据数据敏感程度采用不同强度的加密算法
- 密钥轮换:定期更换加密密钥,降低密钥泄露风险
- 性能监控:监控加密解密操作的性能影响
3.3 统一配置管理
- 将密钥、算法参数等配置项统一管理
- 支持运行时动态更新,无需重启服务
- 建立配置变更审计机制
四、总结
API安全防护是系统安全的重要组成部分。通过合理的签名验证机制可以有效防止请求篡改,而适当的数据加密策略则能保护敏感信息安全。在实际应用中,需要根据业务特点和安全要求,合理选择和配置相应的安全措施,构建多层次的安全防护体系。
这两种安全机制的结合使用,能够显著提升API服务的安全性,为用户提供更加可靠的网络服务保障。