服务间远程请求

防篡改

MD5 与 SHA-256 同为确定性哈希函数,都用于生成数据指纹;两者都具备雪崩效应与固定长度输出。区别在于 MD5 存在可被主动构造的碰撞,已不具备安全性,而 SHA-256 具备强抗碰撞能力,当前仍安全,适用于签名与防篡改等安全场景。

雪崩效应是指:内容一旦被改,指纹就会变化;

MD5主动碰撞是指:不同的内容可以生成相同的MD5指纹,这就导致攻击者可能构造出与目标内容相同的MD5,从而越过目标系统的防篡改验证;

SHA-256 在数学上也可能碰撞,但碰撞可能需要100 亿年以上,因此在工程上等价于不会碰撞,可用于安全场景,而 MD5 已经不具备这个性质。


服务间请求 - Signature 鉴权

客户端发起 POST 请求时,会先对请求体进行序列化与规范化(如字段排序、编码统一等),以保证同一语义的数据在客户端与服务端具有一致的字节表示。

在微服务间调用中,请求体完成规范化后,客户端通过 SHA-256 计算得到请求体的 hash,并将该 hash 与请求路径、HTTP 方法、时间戳、随机数等按照约定规则拼接,使用加密密钥通过 HMAC-SHA256 生成数字签名;随后将签名、相关请求头以及原始 body 一并发送至服务端。

服务端接收到请求后,按相同规则对请求体进行规范化并重新计算 hash,再基于加密密钥生成签名,与请求头中的签名进行比对;若签名一致,则说明请求体未被篡改且来源可信,否则判定为非法请求。同时结合时间戳与随机数校验,可进一步防止重放攻击;当请求体为空时,约定对空字节序列进行 hash 计算,其结果为固定值,从而保证签名流程的一致性与无分支处理。

以上过程就是 Signature 鉴权,Signature 鉴权是验证“调用方身份 + 请求未被篡改”;与之对应的 JWT 鉴权是验证“用户身份(登录态)”;

请求是不是“合法调用方发的”

请求信任 - Signature 鉴权

服务之间发起请求时,要加如下请求头:

X-Remote-Call : 用于区分普通请求

X-Client-Id : 用于标识请求方的身份

X-Timestamp : 请求发起时的时间戳,可用于防止防重放攻击;例如:服务端收到请求后,发现此时间与当前时间相关较远(一般是5分钟),可以直接拒绝请求;

X-Nonce : 一次性随机数,防止重复请求 和 重放攻击

X-Signature : 请求的数字签名,用于校验请求参数是否被被篡改、来源是否可信;


请求一次性性消费

请求体只能被读取一次,这是 Servlet 规范对 HTTP 输入流的设计(基于一次性消费的 InputStream);但在微服务远程调用场景中,服务端通常需要在过滤器中先读取请求体以完成签名验证(如计算 SHA-256 并校验签名),此时请求流已被消费,后续 Controller 将无法再次读取请求体;因此需要通过 SignedRequestWrapper 将已读取的请求体缓存到内存中,并重写 getInputStream()getReader() 方法,使请求体可以被重复读取,从而既满足安全校验,又不影响后续业务处理。


过滤器顺序和鉴权链路

1>. 过滤器的顺序

当服务同时可能被 前端页面 和 其它微服务 调用时,其过滤器链的执行顺序应该是如下这样:

请求进入
↓
Signature 鉴权(当请求头 X-Remote-Call=true 时执行),成功则构建 Service Authentication
↓
JWT 鉴权(当请求头 X-Remote-Calltrue 时执行),成功则构建 User Authentication
↓
Authorization:基于当前 AuthenticationUserAdmin 或 Service)做访问控制(即路由控制)
↓
Controller

Signature 鉴权(服务请求):仅当 X-Remote-Call=true 时执行鉴权,否则跳过;鉴权成功后构建 Service 角色的授权,请写入 spring security 上下文;若校验失败,则直接拒绝(401/403)

JWT 鉴权(用户请求):仅当 X-Remote-Call≠true 时执行,校验 JWT 合法性并解析用户信息;校验通过后构建 User Auth 写入上下文;若无 JWT 或校验失败 → 按未登录/无权限处理


2>. 鉴权链路

请求从客户端到服务端的过程中,HTTPS 已经保证了请求在传输链路中不会被中间人窃听或篡改。


网页端发起的 JWT Token 请求可能会被用户自己的网页脚本、抓包工具等任意修改,因此服务端永远不信任用户端发起的任何请求;对用户端请求,服务端必须进行严格的参数校验与业务约束校验。用户请求一旦离开浏览器进入 HTTPS 传输链路,其内容在传输过程中就是可信未被篡改的,但“请求本身是否合法”仍完全依赖服务端判断。


也就是说,对于用户请求:JWT 负责身份认证,业务层负责数据校验与约束,从而整体保证安全性,因此通常不需要额外引入请求级别的防篡改签名机制;


微服务发起的请求,不应被默认信任,而应被显式验证其身份与来源;因为服务之间的调用通常具备更高权限,一旦被伪造或滥用,影响范围远大于普通用户请求。因此需要引入服务间认证机制(如 Signature、mTLS 等),用于确认“调用方是谁”,并在必要时对请求进行完整性校验与防重放保护(如 timestamp、nonce 等)。这里的“签名”不仅用于防止请求在多级代理、网关链路中被篡改,更核心的作用是防止未授权服务伪造调用请求,确保调用方身份可信,而不是仅依赖网络环境的安全性;


总之,网页客户端请求确实可以被篡改,但这是系统设计的基本前提(客户端不可信),因此通过“身份认证 + 严格校验”来保障安全;而微服务调用则必须通过机制建立“可验证的信任关系”,以防止伪造调用、越权访问以及潜在的链路篡改问题。

举报

© 著作权归作者所有


0