密保问题安全逻辑必须由服务端实现,前端仅负责语义化表单结构与基础交互;问题需动态生成、答案经https提交并哈希存储,禁用localstorage明文保存,修改前须二次验证。

HTML里没法单独实现密保问题的安全逻辑
浏览器端的 HTML 本身不处理验证、不加密存储、也不防重放——密保问题属于后端鉴权环节,前端只负责表单结构和基础交互。硬要在 HTML 里“模拟”安全设置,反而会误导用户以为输入是被保护的。
常见错误现象:type="password" 用在密保答案输入框上;把问题和答案全写死在 HTML 源码里;用 localStorage 存答案明文;提交时没走 HTTPS。
- 密保问题必须由服务端动态生成(比如从题库随机选3题),不能靠 HTML
select静态列出全部选项 - 用户答案必须经 HTTPS 提交,且服务端做哈希比对(不是明文比对)
- 前端可做基础校验(如答案长度、非空),但绝不能替代服务端校验
- 避免在 HTML 注释或
data-属性里泄露题干映射关系(例如data-question-id="q7"对应“你小学班主任名字”,等于白送信息)
怎么写一个合规的密保设置表单结构
核心是语义清晰、无障碍可用、不暴露逻辑,同时为后续 JS 和后端留好接口。
使用场景:用户首次设置或重置密保,在「账号安全」页中嵌入。
示例结构(仅 HTML):
-
name值要和服务端约定一致(如q1_id+a1),避免用中文或空格 - 禁用
autocomplete防止浏览器填充历史答案(密保答案不该被记住) - 不用
type="password"——答案可能是生日、地名等非敏感格式,掩码反而影响输入准确率 - 每个
select必须由 JS 动态加载题干(服务端返回 JSON 列表),禁止写死在 HTML 中
为什么不能用 localStorage 存密保答案
因为 localStorage 是纯前端、无加密、同源即读取——只要页面能执行 JS,就能 localStorage.getItem('security_answer') 直接拿到明文。
性能/兼容性影响:无性能问题,但安全等级归零;所有现代浏览器都支持,正因如此才更危险。
- 哪怕加了简单 base64 或 xor,也算“明文等价”,工具几行代码就能还原
- 扩展程序、恶意脚本、甚至同一域名下的 XSS 漏洞,都能瞬间窃取
- 真正该存的是服务端下发的临时 token(如
setup_token),用于提交时校验本次操作合法性 - 如果非要前端缓存中间状态(比如用户填了一半关了页面),可用
sessionStorage,且关闭标签页即销毁
提交后服务端必须做的三件事
前端表单只是入口,真正的安全防线全在服务端响应逻辑里。
常见错误现象:200 OK 返回后前端就显示“设置成功”,但服务端其实没校验答案长度、没去重、没哈希存储。
- 拒绝空答案、纯空格答案、少于2字符的答案(
a1、a2、a3全部检查) - 三个答案不能完全相同(防止用户填三个“123”应付)
- 答案必须用带 salt 的哈希(如
bcrypt或scrypt)存储,绝不可明文或简单 md5 - 返回响应中不要暴露题干与 ID 的对应关系(例如别返回
{"q1_id": 7, "question": "你小学班主任名字"})
最容易被忽略的一点:密保问题修改必须要求当前登录态二次验证(比如输密码或短信验证码),不能仅凭 session 就允许改。否则一旦账号被短期劫持,攻击者可直接覆盖密保,彻底锁死用户。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











