跨域伪造请求如何规避

wen 网络安全 27

本文目录导读:

跨域伪造请求如何规避

  1. 核心原则:服务端必须验证请求的“真实性”
  2. 综合建议(最佳实践组合)
  3. 绝对不能做的事(易犯错误)
  4. 总结表格

跨域伪造请求(通常指CSRF,跨站请求伪造)是一种常见的Web安全威胁,要有效规避,需从服务端防护前端配合浏览器安全机制三个层面入手,以下是具体、可操作的规避方案:

核心原则:服务端必须验证请求的“真实性”

前端的一切措施(如设置Token)都只是辅助,服务端必须对每一个敏感操作(修改、删除、转账等)进行合法性校验。

使用 Anti-CSRF Token(最经典、最有效)

服务端生成一个随机、不可预测的Token,存储在用户的Session或Cookie中,每次前端发送敏感请求时,必须携带该Token(通常在请求头或请求体中),服务端验证Token是否匹配。

  • 实现方式
    • 前端:从服务端获取Token(例如在页面加载时,嵌入到<meta>标签或JavaScript变量中),在发起请求时(如fetchaxios)手动添加到请求头中。
    • 服务端:验证请求头中的Token与Session中的Token是否一致。
  • 注意:Token必须与服务端Session绑定,并且不能通过Cookie自动发送(避免被攻击者利用Cookie自动携带的特性),Token放在Authorization或自定义请求头中。

同源检查(Origin / Referer 验证)

服务端检查请求头中的OriginReferer字段,判断请求是否来自允许的域名。

  • Origin字段(更推荐):由浏览器自动添加,只包含协议、域名和端口(不含路径),且对于POST请求几乎必定存在,服务端验证Origin是否在白名单中。
  • Referer字段(备选):可能因浏览器隐私设置或被开发者禁用而丢失,可靠性较低。
  • 规则:如果是来自第三方域名(如evil.com)的伪造请求,其OriginReferer必然与你的站点不同,直接拒绝。

自定义请求头(如 X-Requested-With: XMLHttpRequest

利用浏览器同源策略的一个特性:只有JavaScript发起的跨域请求(XHR/Fetch)才能添加自定义请求头,而通过HTML表单提交(伪造CSRF的主要手段)无法添加

  • 实现:前端所有AJAX请求(包括fetchaxios)统一添加一个非标准但常用的请求头,例如X-Requested-With: XMLHttpRequest或你自定义的X-CSRF-TOKEN
  • 服务端:检查该头部是否存在且值正确,如果缺失或错误,则拒绝请求。
  • 注意:这种方法依赖于简单请求预检请求的区别,如果请求是简单请求(如Content-Type: application/x-www-form-urlencoded的POST),浏览器不会发预检请求,此时自定义头部的有效性较弱(但依然比没有好),更可靠的做法是配合Token使用。

二次验证(重验证)

对于高敏感操作(修改密码、删除账号、转账大额资金),要求用户进行二次确认。

  • 方式:弹出验证码(CAPTCHA)、输入当前密码、发送短信验证码或邮箱二次确认链接。
  • 效果:即使CSRF攻击成功,攻击者也无法获取用户的验证码或密码,无法完成操作,这是最后一道防线。

设置 Cookie 的 SameSite 属性(现代浏览器的强力防御)

这是浏览器层面的防御机制,能自动阻止大多数跨站点请求中发送Cookie。

  • SameSite=Lax(推荐,但需注意兼容性):允许在用户点击链接(a标签)、GET表单提交等顶链导航时发送Cookie,但禁止在跨站点的POST表单提交跨站点的Fetch/AJAX请求中发送Cookie,这个模式能覆盖绝大多数CSRF攻击场景(因为攻击者通常通过POST提交表单或发送AJAX请求)。
  • SameSite=Strict:严格模式,完全禁止跨站点请求携带Cookie(包括点击链接),可能影响用户体验(如从邮件点击链接无法保持登录状态)。
  • SameSite=None(需配合Secure,且浏览器显式同意):表示允许跨站点携带Cookie,但必须通过HTTPS,这通常用于需要跨域共享Cookie的场景(如SSO),但会显著增加CSRF风险。

最佳实践:对于登录态相关的会话Cookie,设置为SameSite=Lax;对于非关键但敏感的Cookie,可设置为SameSite=Strict,设置HttpOnlySecure属性是必须的。

使用 JSON API 并强制 Content-Type: application/json

攻击者通过HTML表单(<form>)提交的数据,其Content-Type只能是application/x-www-form-urlencodedmultipart/form-datatext/plain无法设置application/json

  • 实现:所有敏感API只接受Content-Type: application/json,服务端验证请求头中的Content-Type
  • 效果:攻击者无法通过表单提交触发API调用,但要小心,如果API也接受application/x-www-form-urlencoded(例如为了兼容性),则此方法无效。

避免使用 GET 请求进行修改操作

这是最基本的安全编码规范,所有修改、删除、写入操作必须使用POST、PUT、DELETE等非GET方法,因为GET请求的URL容易被嵌入到图片、链接中,且浏览器会直接发起,形成CSRF。

综合建议(最佳实践组合)

  1. 对于所有受登录保护的页面

    • 在服务端生成一个随机Token,存储在Session中。
    • 在页面渲染时,将Token写入一个自定义请求头(例如X-CSRF-Token)或JavaScript变量。
    • 前端所有非GET请求(POST、PUT、DELETE)在发起时,都必须通过JavaScript读取这个Token,并添加到请求头中。
    • 服务端验证请求头中的Token是否与Session中的Token匹配。
    • 同时,将登录后的会话Cookie设置为SameSite=LaxHttpOnly
  2. 对于全站的通用防御

    • 服务端统一验证OriginReferer头部(优先用Origin),如果请求来源不在白名单内,直接拒绝。
    • 强制使用POST/JSON处理所有修改接口,并限制Content-Type。
  3. 对于极高安全要求的操作

    • 加上二次验证(验证码、密码、短信)。

绝对不能做的事(易犯错误)

  • 使用Cookie来存储CSRF Token:绝不要把CSRF Token放在Cookie里,然后通过Cookie自动发送来验证,因为Cookie会被自动携带,攻击者也可以访问到(如果Cookie未设置同源策略),Token必须放在请求头或请求体中,手动发送。
  • 依赖Referer或Origin做唯一验证:它们可能被篡改(虽然很难)或缺失(隐私模式、代理),它们应作为辅助防御,而非唯一防线。
  • 忽略JSONP的GET请求:JSONP本身是GET请求,且允许跨域,如果JSONP接口存在且用于修改数据,则极易被CSRF利用,应避免使用JSONP处理写操作。

总结表格

防御措施 核心机制 防御强度 注意事项
Anti-CSRF Token 服务端生成随机token,前端手动携带 必须服务端验证;token不能存Cookie;需前端配合
同源检查 验证Origin/Referer 中高 Origin更可靠;可作为第二道防线
自定义请求头 利用表单无法添加自定义头部 依赖预检请求;最好配合Token
SameSite Cookie 浏览器限制跨站发Cookie 高(现代浏览器) 需浏览器支持;注意LaxStrict的兼容性
二次验证 重放攻击无法绕过 极高 影响用户体验;仅用于关键操作
JSON API+Content-Type 限制Content-Type为JSON 需服务端严格校验;兼容性风险

核心思路:让攻击者无法构造一个“看起来像是用户自己发出的、且被服务端信任的合法请求”,防御组合拳远胜于单一措施。

抱歉,评论功能暂时关闭!