URL 中传递密码或 token 极不安全,因所有中间环节(日志、缓存、控制台等)均可明文获取;敏感操作必须改用 POST/PUT/PATCH + 请求体传参,并严格校验请求方法与参数来源。
GET 请求里传密码或 token 就是明文裸奔
浏览器地址栏、服务器访问日志、代理缓存、cdn 日志、前端控制台网络面板……所有环节都能直接看到 url 里的参数。哪怕用了 https,也只是加密传输,不解决「参数本就不该出现在 url 里」这个根本问题。
常见错误现象:https://api.example.com/login?username=admin&password=123456 这类请求一发,敏感信息就进了 N 个系统日志;用 history.pushState 拼接带 token 的路由,结果被 Vue Router 或 React Router 记录进 history,再被误分享出去。
- 登录、换绑、重置密码、获取私有资源等操作,一律改用
POST(或PATCH/PUT)+body传参 - 前端发请求时,确认
fetch或axios的method不是'GET',且data/body字段已正确设置 - 后端接口必须校验请求方法:比如 Express 中用
app.post('/login', ...),而不是app.get('/login', ...)—— 同一路由名下GET和POST是完全独立的处理逻辑
路由参数(URL Path)也不安全,别把敏感 ID 当掩护
有人觉得 /user/abc123/edit 比 /user?id=abc123 隐蔽,其实没区别——路径照样进日志、被浏览器记录、可被爬虫抓取。Path 参数和 Query 参数在传输层没有安全性差异。
使用场景:管理后台跳转编辑页、API 获取单条记录等。如果 abc123 是用户 UUID 或手机号哈希,仍属敏感标识,不应暴露在可预测/可枚举的路径中。
- 对非公开资源,优先用服务端 session 或 JWT 鉴权,而不是靠“隐藏路径”来防访问
- 必须通过路径传递上下文时,用一次性、有时效的 token 替代原始 ID,例如
/order/tx_7f9a2b_v2,后端查表映射真实订单号 - 避免在路由中拼接邮箱、身份证片段、token 前缀等可反推的信息,
/reset/ema_abc@def.com这种写法等于主动泄露
前端路由(React Router / Vue Router)默认不拦截 GET 行为
前端路由只是 URL 显示和组件切换机制,它不阻止用户手动在地址栏输入带敏感参数的 URL,也不影响实际 HTTP 请求行为。很多人以为 “用了 SPA 就安全了”,其实完全不是。
常见错误现象:用户复制了 https://app.com/dashboard?token=ey...&debug=true 分享出去;或者开发者用 useNavigate 拼出带 token 的链接用于页面跳转,结果 token 被持久化在 history 中。
- 禁止用
searchParams或query传递认证凭据、权限标记、临时密钥 - 需要跨页面传参时,改用
state(如navigate('/page', { state: { data } })),该数据仅存在内存中,不出现在 URL 或 history.state 以外的地方 - 服务端渲染(SSR)项目要额外注意:
location.search在首屏即解析,若未过滤敏感字段,可能直接打日志或参与服务端计算
后端必须做请求方式白名单 + 参数来源校验
只靠前端约束毫无意义。攻击者绕过 JS 直接发 curl,就能把任何参数塞进 GET 请求。后端才是最后一道防线。
性能影响极小,但漏掉就是高危漏洞。比如一个本该只接受 POST 的支付回调接口,如果允许 GET,攻击者可能构造恶意链接诱骗用户点击,触发重复扣款。
- 对每个接口明确声明允许的方法:Express 用
app.post()+app.all()拦截非法方法并返回405 Method Not Allowed - 拒绝从
req.query(GET 参数)读取本应来自req.body(POST 内容)的字段,哪怕字段名一样也要严格区分来源 - Nginx 层可加简单限制,例如
if ($request_method !~ ^(POST|PUT|PATCH|DELETE)$) { return 405; },但不能替代应用层校验
真正难的不是加几行代码,而是团队里每个人都得明白:URL 是公共信道,不是保险箱。只要参数进了 path 或 query,就等于放弃了保密责任。










