新闻

API接口安全防护:筑牢数字世界的第一道防线

新闻 2026-05-16 0 次浏览

API安全:从Token到签名

随着企业业务规模的扩大,API接口安全成为开发者必须面对的核心问题。无论是对接第三方服务(如支付、地图API),还是对外提供开放接口,安全设计都至关重要。本文将系统介绍两种主流解决方案:Token机制和接口签名验证,并通过代码示例展示最佳实践。

Token机制详解

Token方案是Web开发中最基础的鉴权方式,其核心流程包括:

  1. 用户登录成功后,服务端生成唯一凭证Token
  2. 客户端在后续请求头中携带Token
  3. 服务端验证Token有效性后处理业务

生产环境中,Token通常存储在Redis中并设置2小时有效期。虽然Token方案能有效防止数据爬取,但在高并发场景下存在明显缺陷——当Token过期瞬间,刷新Token的过程会导致大量请求失败。某大型互联网公司的实际案例显示,这种机制在流量高峰期可能引发服务抖动。

接口签名方案

相比Token,接口签名更适合高安全性要求的场景,其核心参数包括:

  • appid/appsecret:应用标识和密钥,用于加密签名
  • timestamp:请求时间戳(有效期为5分钟)
  • nonce:随机数,防止重放攻击
  • signature:最终签名值

签名算法采用双重MD5加密:

//第一次加密
String step1 = md5(method + url + body);
//第二次加密
String signature = md5(appsecret + timestamp + nonce + step1);

这种方案在需要与第三方进行复杂对接时尤为可靠,但计算复杂度较高,不建议用于前后端交互场景。

JWT实现示例

以下是基于JWT的Token工具类实现:

public class JwtTokenUtil {
    private static final String KEY = "q3t6w9z$C&F)J@NcQfTjWnZr4u7x";
    private static final long EXPIRATION = 7200000; //2小时

    public static String createToken(String content) {
        return "Bearer " + JWT.create()
            .withSubject(content)
            .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION))
            .sign(Algorithm.HMAC512(KEY));
    }

    public static String verifyToken(String token) throws Exception {
        return JWT.require(Algorithm.HMAC512(KEY))
            .build()
            .verify(token.replace("Bearer ", ""))
            .getSubject();
    }
}

使用注意事项:

  • 可将基础用户信息存入Token,减少数据库查询
  • 严禁存储敏感数据,Token内容可被解析

签名验证拦截器

完整的签名验证流程应包含:

public class SignInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, 
                            HttpServletResponse response, 
                            Object handler) throws Exception {
        //1. 验证appid
        String appId = request.getHeader("appid");
        String appSecret = getAppSecret(appId);
        
        //2. 验证时间戳(5分钟有效期)
        long timestamp = Long.parseLong(request.getHeader("timestamp"));
        if(Math.abs(System.currentTimeMillis() - timestamp) > 300000) {
            throw new CommonException("timestamp已过期");
        }
        
        //3. 防重放验证
        String nonce = request.getHeader("nonce");
        if(redisUtil.exist(appId + "_" + timestamp + "_" + nonce)) {
            throw new CommonException("请勿重复提交");
        }
        
        //4. 签名校验
        String signature = request.getHeader("signature");
        String computed = SignUtil.getSignature(
            request.getMethod(),
            request.getRequestURI(),
            StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8),
            timestamp, nonce, appSecret
        );
        
        if(!signature.equals(computed)) {
            throw new CommonException("签名验证失败");
        }
        
        //5. 记录请求标记
        redisUtil.save(appId + "_" + timestamp + "_" + nonce, computed, 300);
        return true;
    }
}

最佳实践建议:

  1. 对内接口使用JWT + Token机制
  2. 对外合作优先选择签名方案
  3. 关键操作必须实现防重放攻击
  4. 密钥管理采用分级隔离策略

这两种方案可以结合使用:内部系统采用Token验证效率更高,而开放接口则使用签名确保安全性。开发者应根据实际业务场景选择合适的方案,在安全性和性能之间取得平衡。

点击查看文章原文
上一篇
26个进阶玩法,助你的ChatGPT效率翻倍
下一篇
Java生鲜电商架构 - API接口token、timestamp、sign的具体实现与设计
返回列表