后端必须校验readonly字段,因其可被浏览器开发者工具、js脚本或curl等任意绕过;需查数据库还原业务意图、校验值合法性、比对上下文一致性、拒绝非预期变更,并注意框架特性与边界情况。

readonly 属性不提供任何防篡改能力,后端必须重新校验字段值是否合法且未被绕过。
为什么 readonly 字段仍需后端校验
浏览器提交时,readonly 字段的值照常进入 FormData、serializeArray() 或 URL 查询参数——这是规范行为,不是漏洞。用户可通过以下任意方式绕过:document.getElementById("price").value = "1"、右键粘贴、开发者工具删掉 readonly 属性、用 curl 直接发请求。只要字段参与业务逻辑(如价格、数量、用户 ID),后端就必须做等价校验。
后端校验的关键检查点
不能只比对“值是否为空”或“类型是否为数字”,而要还原前端只读逻辑的业务意图:
- 查原始数据源:比如表单中
order_id设为readonly,后端应从数据库查出该订单当前状态,确认用户是否有权操作此订单,而非仅信任提交的order_id值 - 校验值是否在合法范围内:如
discount_rate是只读显示为0.05,后端需验证数据库中该订单对应的实际折扣率是否确为5%,而不是直接接受请求体里的0.99 - 比对上下文一致性:若
user_role字段设为readonly,后端应结合当前登录用户的 Session/Token 中的角色信息交叉验证,防止伪造字段值提升权限 - 拒绝非预期字段变更:对明确标记为只读的字段,后端可记录其原始值(如从数据库读取),提交时发现不一致即视为篡改,直接拒收并记日志
常见框架中的实现注意项
不同框架对只读字段的处理惯性容易掩盖问题:
- ThinkPHP 的
$readonly属性仅影响save()和update()时的字段过滤,但若用data($data, true)强制赋值、或执行原生 SQL,则完全失效 - Django 的
ModelForm若将字段设为disabled=True,该字段不会出现在form.cleaned_data中;但若用readonly渲染,字段会进cleaned_data,此时必须在clean_<field>()</field>方法里加校验逻辑 - Spring Boot 的
@Valid不识别 HTML 的readonly语义,需手动在 Controller 或 Service 层调用校验方法,例如对比 DB 查询结果与请求参数
最容易被忽略的边界情况
真正出问题的往往不是明显被改的字段,而是那些“看起来没动、其实已被间接污染”的值:
- 时间类字段(如
created_at)设为readonly,但攻击者可能通过修改关联字段(如status)触发服务端自动更新该时间戳,造成逻辑错乱 - 前端用 JS 动态计算并填入
total_amount后设为readonly,后端若只校验单个字段,而不重算unit_price * quantity + tax,就无法发现中间环节被篡改 - 多步表单中,上一步的只读字段在下一步被隐藏并复用 name,但后端未做步骤状态校验,导致跳过校验直接入库
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











