本文目录导读:

参数篡改是一种常见的Web安全威胁,攻击者通过修改客户端发送的请求参数(如URL查询字符串、表单字段、Cookie、HTTP头等)来达到越权、数据窃取或系统破坏的目的,防护的核心是对每一条到达服务端的参数都进行严格的校验。
以下是从代码、架构到运维层面的全方位防护校验方案:
最核心原则:永远不信任客户端
任何来自客户端(浏览器、APP、桌面端)的数据都是不可信的,所有校验必须在服务端进行,客户端的校验仅用于提升用户体验,不具安全性。
参数级校验:明确数据边界
类型与格式校验
- 强类型语言:使用DTO(数据传输对象)或实体类进行类型绑定。
- 例:
int age = Integer.parseInt(request.getParameter("age"));如果参数不是整数,直接抛出异常。
- 例:
- 正则表达式:对字符串类型参数进行格式匹配。
- 邮箱:
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ - 手机号:
^1[3-9]\d{9}$
- 邮箱:
- 枚举校验:对于状态、类别等有限集合的参数,使用枚举或白名单列表。
- 例:
status只能是[0, 1, 2],如果传了999,直接拒绝。
- 例:
长度与范围校验
- 数值范围:
0 < price <= 10000,防止越界注入或逻辑错误。 - 字符串长度:限制输入最大长度,防止缓冲区溢出或存储攻击。
- 例:
username.length() <= 50
- 例:
- 数组长度:限制一次提交的批量数量(如最大100条),防止批量篡改或DoS攻击。
枚举值与白名单校验
- 危险参数:如
role=admin、isVip=true、action=delete。 - 方案:服务端必须内置映射关系,而非直接信任客户端传来的值。
- 错误做法:根据
?role=admin直接赋予管理员权限。 - 正确做法:从Session或Token中解析当前用户的真实角色,忽略
role参数。
- 错误做法:根据
业务逻辑一致性校验
- 不可编辑字段:如订单金额、积分、创建时间等,前端不展示或展示为只读,后端应忽略或覆盖前端传来的该参数值。
- 计算校验:如果参数存在内在关联,需校验一致性。
- 例:
totalPrice = unitPrice * quantity,后端应重新计算totalPrice,与前端传入值做比对,若不匹配则拒绝。
- 例:
会话与权限级防护:防御越权篡改
基于Session/Token的权限校验
- 用户ID篡改:攻击者尝试修改
userId=100来查看他人信息。- 防护:永远不要从请求参数中读取当前用户ID,从服务端Session或JWT Token中解析
当前登录用户ID。 - 例:
Long currentUserId = SecurityContextHolder.getCurrentUser().getId();
- 防护:永远不要从请求参数中读取当前用户ID,从服务端Session或JWT Token中解析
资源所有权校验
- 即使攻击者知道了正确的用户ID,也要校验他是否有权操作该资源。
- 例:修改订单
orderId=888,需校验order.userId == currentUserId。
CSRF(跨站请求伪造)防护
- 攻击者诱导用户点击一个恶意链接,利用用户的登录状态发送篡改参数的请求。
- 防护:
- 使用CSRF Token(前后端分离常见使用)。
- 使用
SameSite=Strict或Lax的Cookie属性。 - 关键操作(支付、删除)使用二次验证(如短信验证码)。
参数传递与签名机制:防止中间人篡改
使用数字签名(HMAC/RSA)
- 原理:将参数按一定规则排序后,与密钥拼接,计算哈希值(MD5/SHA256)作为签名。
- 流程:
- 服务端下发一个
secretKey或appId+secret。 - 客户端对参数排序(如按字母顺序)并拼接成
str=A=1&B=2&C=3。 - 计算
sign = HMAC-SHA256(secret, str)。 - 服务端收到请求后,用同样的
secret计算并比对sign。
- 服务端下发一个
- 效果:参数被篡改后,签名校验失败,直接拒绝。
防重放攻击(时间戳+随机数Nonce)
- 即使参数及签名被拷贝,攻击者在短时间内重新发送请求。
- 方案:
- 请求携带
timestamp(Unix毫秒时间戳)。 - 服务端比对时间差(如
|now - timestamp| >= 5分钟则拒绝)。 - 结合
nonce(一次性随机字符串),服务端记录已使用的nonce,防止5分钟内重复使用。
- 请求携带
参数加密(敏感数据)
- 敏感参数:如银行卡号、密码、身份证号。
- 方案:使用对称加密(AES)或非对称加密(RSA)对参数整体或部分加密,服务端解密后再使用,攻击者无法解密也就无法篡改。
后端架构与框架级防御
使用成熟的校验框架
- Java:
Bean Validation (JSR 303/380)配合注解(@NotNull,@Size,@Pattern,@Digits)。 - Python:
Pydantic,marshmallow。 - Node.js:
Joi,express-validator。 - Go:
validator包。 - 所有语言:Web框架自带的校验中间件(如Spring的
@Validated, Django的ModelForm)。
输入净化与转义
- SQL注入防护:使用参数化查询(Prepared Statement),禁止拼接SQL字符串。