CSRF和跨域问题CORS

9 阅读3分钟

原来只知道有CORS是因为浏览器同源策略引起的,所以如果前端调用后端Restful API的时候浏览器会报跨域的问题;

image.png 看完CSRF相关的内容,跨站点请求伪造,即便有同源策略,浏览器会拦截响应,但是该执行的API还是已经执行过了。

CORS 是浏览器为了解决跨域请求的问题而设计的一种机制,后端通过设置 HTTP 响应头(如 Access-Control-Allow-Origin)告诉浏览器:我允许这个域的请求访问我的资源。

“简单请求”:

符合以下条件的请求,浏览器直接发起请求,不会预检

  • 方法是 GET、POST 或 HEAD;
  • Content-Type 限于:application/x-www-form-urlencoded, multipart/form-data, text/plain
  • 无自定义请求头;

这些请求如果不被 CORS 允许,浏览器会拦截响应(但请求已经发送了)

🔍 示例:简单请求跨域时依旧执行 API

const formData = new URLSearchParams();
formData.append('email', email);
formData.append('name', name);
formData.append('password', password);

fetch(`${API_URL}/auth/register`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded', // ✔️ 属于简单请求
  },
  body: formData,
});

上面的请求是跨域的,而且会有跨域问题,但是仍旧会创建一个新的用户,用户会被保存到数据库; 这是一个典型的“简单请求”,即使跨域时 CORS 没设置允许,浏览器也会把请求发送出去!只是响应内容会被拦截,JavaScript 拿不到响应数据。

⚠️ “非简单请求”:

如使用 PUT、DELETE 方法或带自定义请求头的 POST 请求,会先发送一个预检请求(OPTIONS) ,询问服务器是否允许,再决定是否发送真正的请求。

🔥 和 CORS 的关系?

  • CSRF 攻击通常是“同源策略绕不过”的,因为攻击的页面和目标 API 是跨域的。
  • 但是跨域的 POST 请求(简单请求)是会直接发出的,哪怕响应被浏览器拦截,后端逻辑已经执行了

🔐 安全建议

same site cookie只允许顶级域名相同的情况下携带cookie,不适用于前后端分离且前后端域名不同的情况; 这时后端设置的sameSite是None;

//前端代码
fetch("https://api.backend.com/api/xxx", {
  method: "POST",
  credentials: "include", // 👈 关键点:允许浏览器带上 Cookie
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify(data),
});
//后端代码
res.cookie("backendToken", token, {
  httpOnly: true,
  secure: true,         // 必须是 HTTPS 才能使用 SameSite=None
  sameSite: "None",     // 明确允许跨站携带 Cookie
});

由于你在跨站传递 Cookie,浏览器已不再默认信任行为,所以要注意:

  • 使用 https://,不要部署在 HTTP 上。
  • 后端验证 OriginReferer 头,配合 CSRF Token 做双重验证(提高安全性)。
  • 如果使用 JWT,尽量使用短有效期 + Refresh Token 机制。

🔐 前端安全防御方法汇总

1. 防止 XSS(跨站脚本攻击)

  • 输入过滤 + 输出转义

    • 所有用户输入进行严格校验(白名单优先)。
    • 对动态插入 DOM 的内容使用转义(如 innerText 替代 innerHTML)。
  • 使用安全框架

    • React、Vue 默认对绑定内容进行转义。
  • Content Security Policy(CSP)

  • 限制可执行的脚本来源,例如:

  • HTTP-ONLY cookie防止cookie泄漏

Content-Security-Policy: script-src 'self'

2. 防止 CSRF(跨站请求伪造)

  • 使用 SameSite Cookie 策略

    • 推荐设置:
    Set-Cookie: token=xxx; SameSite=Strict; HttpOnly; Secure
    
    • Strict: 拒绝第三方携带 Cookie,前后端不分离时使用。

    • Lax: 支持 GET 导航请求,适合大多数表单场景。

  • 配合 Token 校验

    • 前端每次请求带上 CSRF Token,在服务端验证。
  • 禁止第三方表单提交

    • 使用 X-Requested-With: XMLHttpRequest 检测是否来自前端代码。
  • 正确使用DOM操作

    • 使用 textContent / innerText,不要用 innerHTML 插入不可信内容。