服务端校验是唯一可信防线,客户端仅作体验优化;必须在api入口统一强校验,结合类型、范围、格式三重检查,并与数据库定义对齐。

客户端校验纯属心理安慰,服务端才是唯一可信防线。双重校验不是“两边都做一遍”,而是客户端做轻量提示、服务端做强制拦截——后者漏掉一个字符,整个防护就归零。
为什么不能只信前端校验
攻击者根本不会打开你的网页,直接用 curl、Postman 或 Burp Suite 发请求,绕过所有 JS 校验、HTML pattern 和禁用属性。前端能做的只有改善用户体验:比如输入框实时提示“用户名只能含字母数字”,但后端必须把 "admin' OR '1'='1" 当非法输入直接拒收。
- 浏览器可被禁用 JS,
input的type="number"可被绕过(改请求体即可) - 任何基于 DOM 的过滤(如
oninput删除单引号)在请求发出前就失效 - 前端正则(如邮箱校验)若和服务端不一致,会引发逻辑矛盾或误拦
服务端校验必须在入口处完成
所有 API 请求在到达数据库操作前,必须经过统一校验层。推荐使用结构化验证工具,在路由解析后、业务逻辑前拦截非法数据。
- Python 用
Pydantic:定义username: str = Field(pattern=r'^[a-zA-Z0-9_]{3,20}$'),非法字段直接返回422 Unprocessable Entity - Go 用
go-playground/validator:对 struct 字段加validate:"required,min=1,max=50,alphanum"标签 - Java Spring Boot 用
@Valid+@NotBlank等注解,配合全局@ControllerAdvice拦截MethodArgumentNotValidException - 校验失败不记录日志到响应体,避免暴露规则(如“密码需含大小写字母”可能助攻击者爆破)
哪些字段必须强校验,哪些不能简单过滤
类型和边界明确的字段(ID、手机号、邮箱)必须严格校验;而搜索词、富文本等模糊字段,绝不能靠 str_replace("'", "''") 或黑名单关键词(如 exec、union)来防御——这些极易被编码、大小写、注释符绕过。
-
id参数:必须转为整型,int(id)失败即400,不传给 DAO 层 -
phone字段:用正则^1[3-9]\d{9}$,不接受带括号、空格、+86 前缀的“友好格式” -
search字段:不校验内容,但强制走参数化查询;若需模糊匹配,用LIKE ?而非拼接"%"+keyword+"%" - 禁止用
mysqli_real_escape_string()替代参数化查询——它只解决单引号问题,对ORDER BY后的列名、LIMIT后的数字完全无效
真正容易被忽略的点
很多人以为“只要用了参数化查询,校验就可松一点”,这是危险错觉。参数化只防 SQL 注入,不防业务逻辑漏洞。比如用户能通过修改 status 参数把别人订单改成“已发货”,这属于越权,和 SQL 注入无关,但同样源于未校验字段语义。
- 所有外部输入,无论是否进 SQL,都要先过类型+范围+格式三重检查
- 校验逻辑必须和数据库字段定义对齐(如 DB 中
email是VARCHAR(254),校验也应限制长度 ≤254) - 不要在 DAO 层补校验——那意味着非法数据已经穿过控制器、服务层,污染了调用栈











