readonly根本防不住脚本注入、XSS、CSRF及用户粘贴、拖拽、JS赋值、开发者工具修改;它仅禁用键盘输入与删除,且值照常提交,本质是UI提示而非安全机制。

input的readonly属性根本防不住什么
它只阻止键盘输入和删除,对粘贴、拖拽、JS赋值、开发者工具删属性完全无效。浏览器提交时,readonly字段的值照常发送——这不是漏洞,是设计如此。
常见误判场景:
- 用户右键粘贴覆盖原值,
readonly不拦截 - 控制台执行
document.getElementById("id").value = "hacked",立刻生效 - 开发者工具里删掉
readonly属性,字段立即可编辑并提交新值
readonly仅对text、password、email、url、number、date等文本类input及textarea生效;加在checkbox、radio、hidden、select上会被浏览器直接忽略。
最致命的坑:和disabled混用。一旦同时存在,disabled会压制readonly,导致该字段既不可编辑,也不会出现在FormData或表单提交参数中——后端收不到值,接口直接报400或空指针。
立即学习“前端免费学习笔记(深入)”;
type="url"不是安全开关,只是体验优化
type="url"只做基础格式校验(比如必须含协议或域名结构),但无法防止javascript:、data:伪协议、开放重定向或XSS载荷。它本质是语义提示+移动端键盘优化,不是安全机制。
典型风险点:
- 用户输入
javascript:fetch("/steal?c="+document.cookie),现代浏览器可能拦截,但旧版或特定上下文仍可能触发 - 输入
https://evil.com/@example.com绕过简单正则校验,造成钓鱼 - 服务端若未做URL规范化(如补全
http://、校验协议白名单、解析host是否可信),前端校验形同虚设
增强防护建议:
- 客户端可用
pattern="https?://.+"+title="请输入合法网址"提升提示精度 - 服务端必须用专业库(如Python的
urllib.parse、Node.js的url-parse)解析并校验scheme、hostname、path - 输出到HTML属性(如
<a href="...">)前,需按上下文做HTML实体编码
autocomplete="off"对隐私保护效果有限
设置autocomplete="off"只能提示浏览器“不要自动填充”,但不强制。Chrome 76+已忽略该属性对password字段的控制,Firefox和Safari也逐步弱化支持。它防不住用户手动复制粘贴,更防不住开发者工具查看DOM或内存中残留的明文值。
真正需要保护的字段(如密码、身份证号、银行卡号)应:
- 前端避免在
value属性中硬编码敏感值(哪怕临时) - 禁用
autocomplete的同时,配合autocapitalize="none"、autocorrect="off"减少干扰 - 服务端绝不记录原始密码;身份证/银行卡号必须脱敏存储(如仅存后四位+哈希)
- 关键操作(如支付)必须二次验证(短信、生物识别),不能仅靠表单字段隔离
注意:autocomplete="new-password"比"off"更可靠,适用于注册页密码确认字段。
所有用户输入都必须走服务端净化,前端只是辅助
任何把用户输入拼进HTML的行为(innerHTML、document.write、Vue的v-html、React的dangerouslySetInnerHTML)都是高危操作。哪怕只是渲染评论里的<img src="x" onerror="alert(1)">,也会触发脚本执行。
正确做法分三层:
- 输入层:对
input值不做信任,禁止直接插入DOM;用textContent替代innerHTML显示纯文本 - 净化层:富文本场景必须用白名单库(如
DOMPurify.sanitize()、Python的bleach.clean()),只允许p、br、strong等安全标签,且严格校验a[href]协议为https?或/ - 输出层:模板引擎默认转义(如Jinja2的
{{ user_input }})必须保持启用;|safe只在100%确认已净化后才可使用
最容易被忽略的一点:CSP头(如Content-Security-Policy: script-src 'self')不是补丁,它无法阻止onerror、href="javascript:"这类内联事件泄露数据——这些必须靠输入过滤和输出编码来根除。



















