🔐 跨域(CORS)与 CSRF:你以为的安全,真的安全吗?

🔐 跨域(CORS)与 CSRF:你以为的安全,真的安全吗?

在现代 Web 开发中,前后端分离已成为主流架构,随之而来的跨域问题也让开发者们不得不与 ​CORS(跨源资源共享,Cross-Origin Resource Sharing)​​ 打交道。

很多开发者配置 CORS 的初衷很简单:​让前端网站能正常访问后端 API 数据。​​ 但如果你因此认为:"只要配置了 CORS,我的接口就安全了",那你就低估了 Web 安全的复杂性。

本文将带你深入探讨:

  • 什么是跨域?为什么浏览器要限制它?
  • CORS 是如何"允许跨域"的?它真的能保护我的后端数据吗?
  • 如果我允许所有来源访问(CORS_ALLOW_ALL_ORIGINS = True),会发生什么?
  • 为什么即使有 CORS,恶意网站仍可能通过 Nginx 代理等方式调用我的接口?
  • 什么是 CSRF?为什么它才是真正防御恶意请求的关键?
  • 为什么 Django 默认有 CSRF 防护,而 FastAPI 没有?
  • 如何在 FastAPI 中实现类似 Django 的 CSRF 保护?

一、什么是跨域?为什么浏览器要限制它?

跨域问题来源于浏览器的核心安全机制 ------ ​同源策略(Same-Origin Policy, SOP)​

什么是同源?

如果两个 URL 的 ​协议(http/https)、域名(例如 example.com)、端口(如 80 或 443)​ ​ 完全一致,那么它们就是同源的。反之,则是不同源

例如:

  • http://localhost:3000http://api.example.com 是不同源的;
  • https://your-site.comhttps://your-site.com:8080 也是不同源的(端口不同)。

浏览器的默认行为:

当你的前端页面(比如运行在 http://localhost:3000)尝试通过 ​AJAX / Fetch ​ 请求访问不同源的后端 API(比如 http://api.example.com)时,​浏览器默认会阻止前端 JavaScript 读取响应内容,尽管请求本身会正常发送到服务器。

✅ 请求会发到后端,但 ✅ 浏览器会根据响应头决定是否把数据交给前端 JS。

这就是同源策略,它的目的是防止恶意网站窃取用户数据。


二、CORS 是什么?后端如何"允许跨域"?

为了解决跨域问题,让浏览器"放行"某些外部域名的请求,后端可以通过设置 HTTP 响应头来声明:"我允许哪些网站跨域访问我"。

这就是 ​CORS(Cross-Origin Resource Sharing,跨源资源共享)​

举个例子(Django 中常见配置):

使用 django-cors-headers 库,你可以通过如下响应头告诉浏览器:

arduino 复制代码
Access-Control-Allow-Origin: https://your-frontend.com

意思是:只有来自 https://your-frontend.com 的请求,我才会允许浏览器把响应数据交给它的 JavaScript。


三、后端开启 CORS,是否有安全风险?

是的,有风险,特别是配置不当的时候。​

常见高风险配置:

  • Access-Control-Allow-Origin: *(允许任意网站访问)
  • Access-Control-Allow-Credentials: true(允许携带 cookies) 与 * 同时使用(浏览器禁止!)
  • 没有对敏感接口做 CSRF 保护

潜在风险包括:

  1. 敏感数据泄露:如果你的 API 返回用户资料等敏感信息,且允许任意跨域访问,那么任何网站的前端 JS 都可能拿到这些数据。
  2. CSRF 攻击风险上升:如果接口支持修改操作(如 POST/PUT/DELETE),并且允许跨域携带 cookies,但没有 CSRF Token 校验,攻击者可能诱导用户发起恶意请求。
  3. 恶意网站滥用 API:即使没有直接窃取数据,攻击者也可以通过合法跨域请求,频繁调用你的接口,造成资源浪费或业务逻辑被滥用。

四、如果我配置了 CORS_ALLOW_ALL_ORIGINS = True,是不是意味着所有网站都能调用我的接口?

✅ ​是的,从浏览器角度来看:如果后端允许所有来源(比如通过 Access-Control-Allow-Origin: * 或 Django 中设置 CORS_ALLOW_ALL_ORIGINS = True),那么任何网站(如 https://evil.com)的前端 JS 都可以向你的 API 发送请求,并获取响应。​

⚠️ 但这仅仅是浏览器不阻止,​不代表你的接口是安全的!​


五、那为什么通过 Nginx 反向代理,恶意网站仍然能调用我的接口,甚至带上我的 Cookies?

关键点:​CORS 是浏览器机制,不是网络层防护!​

  • 即使你没有配置 CORS,或者配置了允许所有来源,恶意网站仍然可以通过服务端代理(如 Nginx)、Postman、curl、自己的程序,直接访问你的后端接口。​
  • 如果用户已经登录,浏览器或代理请求可能会自动携带 Cookies,导致用户身份被冒用。

🔐 ​这就是为什么:跨域限制只能防止浏览器中的恶意 JS 偷数据,但挡不住真正有技术能力的攻击者直接调用你的接口。​


六、那 CSRF(跨站请求伪造)防护就很重要了,对吧?

✅ ​完全正确!​

什么是 CSRF 攻击?

CSRF(跨站请求伪造)是指:攻击者诱导用户访问恶意网站,该网站通过浏览器自动携带用户的登录凭证(如 Cookies),向目标网站(比如你的银行 API)发起恶意请求,比如转账、修改密码等。

为什么 Django 默认有 CSRF 保护,而 FastAPI 没有?

  • Django 偏向服务端渲染 + Cookie Session 模式,容易受到 CSRF 攻击,所以默认启用了 CSRF Token 校验。
  • FastAPI 更多用于前后端分离 + Token(如 JWT)认证 ,Token 一般放在 HTTP Header(如 Authorization: Bearer xxx)中,浏览器不会自动携带,因此 CSRF 攻击几乎无效,所以 FastAPI 默认不提供 CSRF 保护

但这并不意味着 FastAPI 不安全,而是它所应对的使用场景天然降低了 CSRF 风险。


如果你在 FastAPI 中使用了 ​基于 Cookie 的身份认证(比如传统 Session、Token 存 Cookie)​ ,那么你 ​必须手动实现 CSRF 保护,否则将非常危险。

方法一:使用第三方库 fastapi-csrf-protect

这是目前较为成熟的解决方案,使用方式类似 Django 的 CSRF 中间件。

安装:
复制代码
pip install fastapi-csrf-protection
基本使用:
python 复制代码
from fastapi import FastAPI, Depends, Request
from fastapi_csrf_protect import CsrfProtect
from fastapi_csrf_protect.exceptions import CsrfProtectError

app = FastAPI()
csrf_protect = CsrfProtect()

@app.on_event("startup")
async def startup():
    await csrf_protect.init()

@app.exception_handler(CsrfProtectError)
def csrf_protect_exception_handler(request: Request, exc: CsrfProtectError):
    return JSONResponse(status_code=403, content={"detail": "CSRF token missing or invalid"})

@app.post("/protected")
async def protected_route(request: Request, csrf_token: str = Depends(csrf_protect)):
    return {"message": "CSRF 校验通过!"}

前端需要:

  • 从 Cookie 或页面中获取 CSRF Token;
  • 在请求头(如 X-CSRF-Token)中将其发送给后端。

  1. 后端在用户登录后生成 CSRF Token,存入 Cookie 或 Session;
  2. 前端从 Cookie 读取 Token,然后在每次敏感请求的 Header(如 X-CSRF-Token)中携带;
  3. 后端校验 Header 中的 Token 是否与 Cookie 中的一致,不一致则拒绝请求。

八、总结:跨域 ≠ 安全,CORS 只是第一道防线

机制 作用 是否能防恶意调用 是否默认安全 是否需要额外防护
CORS 控制哪些外部网站的前端 JS 可访问你的 API ❌ 不能防服务端/代理调用 ⚠️ 弱防护 ✅ 必须合理配置
CSRF Token 防止恶意网站伪造用户身份发起请求 ✅ 能有效防御 ✅(Django 默认有) ✅(FastAPI 需手动)
身份认证(JWT / Session)​ 确认用户身份合法性
网络层防护(Nginx / 防火墙)​ 限制访问来源 IP / 接口暴露面 ⚠️ 依赖配置 ✅ 推荐

✅ 最佳实践建议

  • 不要依赖 CORS 作为唯一安全机制。​
  • 敏感接口一定要使用身份认证(如 JWT、Session) + 权限控制。​
  • 如果你的接口依赖 Cookie,请务必加上 CSRF Token 校验。​
  • 在 FastAPI 中使用 Cookie 认证时,推荐使用 fastapi-csrf-protect 或手动实现 CSRF 校验。​
  • 永远不要使用 Access-Control-Allow-Origin: * 处理需要身份验证的接口。​
  • 使用 HTTPS、接口限流、操作日志等多种手段构建多层次安全防护。​

🔒 一句话总结:

跨域(CORS)是浏览器为了保护用户数据而设计的一种浅层防护机制,它不能阻止真正的黑客或服务端直接访问你的后端接口。如果你使用 Cookie 类认证,CSRF 防护才是真正防御恶意请求的关键,无论是 Django 还是 FastAPI,都应当引起足够重视。安全,永远是一个多层次、立体化的工程。​


如你喜欢,这篇文章还可以扩展为系列内容,比如:

  • 《Django 安全实战:如何正确配置 CORS 与 CSRF》
  • 《FastAPI 安全指南:身份认证、JWT、CSRF 与接口防护》
  • 《从同源策略到 OAuth2:一文读懂 Web 安全的核心机制》

欢迎继续交流,一起打造更安全的 Web 应用!🚀

相关推荐
Goboy12 小时前
登录机制五兄弟,关系乱到我怀疑人生!
后端·面试·架构
再吃一根胡萝卜12 小时前
跨域本身其实是一种浏览器提供的安全机制,那如果后端主动允许跨域访问,会不会带来安全隐患?
后端
再吃一根胡萝卜12 小时前
CSRF 攻击与防护
后端
东百牧码人13 小时前
将 Ocelot 与 Serilog 和 Loki 集成可以实现强大的日志收集和分析能力
后端
_風箏13 小时前
SpringBoot【集成generator】代码生成+knife4j接口文档(2种模板设置、逻辑删除、字段填充 含代码粘贴可用)保姆级教程
数据库·后端
MaxHua13 小时前
微服务认证授权进阶指南:从基础方案到零信任架构
后端·面试
MrSYJ13 小时前
学完涨工资的技巧1:Spring Authorization Server如何做到只处理oauth相关请求
java·后端·spring cloud
LSTM9713 小时前
使用Java读取Word文档:实战指南
后端
_風箏13 小时前
SpringBoot【集成ClickHouse】clickhouse+mybatis-plus配置及使用问题说明(含建表语句、demo源码、测试说明)
数据库·后端