前后端分离架构把会话维护、权限校验、数据过滤这些安全职责从服务端渲染的“黑盒”里剥离出来,直接暴露在浏览器与API的交互链路上。攻击者不再需要研究HTML表单的隐藏字段或服务端模板的渲染逻辑,只需要用浏览器开发者工具就能完整观察前端如何调用接口、如何携带凭证、如何组织请求体。这意味着原本依赖“服务端不输出敏感字段”的防护思路基本失效,因为前端代码里很可能已经写死了接口地址、参数结构甚至部分业务规则。真正要解决的是三个层面的问题:凭证如何存、接口如何验、数据如何滤。
令牌存储与传输的边界控制JWT在前后端分离项目里几乎成了标配,但大多数安全问题的起点不是JWT本身,而是前端把令牌放在localStorage里。localStorage可以被任何同源脚本读取,一旦存在XSS漏洞,攻击者不需要绕过HttpOnly限制就能直接拿走令牌。更隐蔽的问题是,很多团队把刷新令牌也放在localStorage,导致短期访问令牌的过期时间形同虚设。解决方案不是简单地把令牌塞进Cookie,而是区分访问令牌与刷新令牌的生命周期和存储位置。
访问令牌适合放在内存中,页面刷新后重新通过刷新令牌获取。刷新令牌应放在HttpOnly、Secure、SameSite=Strict的Cookie中,并且设置较短的路径范围。这样即使前端脚本被注入,攻击者拿不到刷新令牌,只能利用当前内存中的访问令牌,而访问令牌的过期时间控制在十五分钟以内,攻击窗口被大幅压缩。接口层需要配合检测访问令牌的过期状态,前端在收到401响应时统一走刷新流程,而不是每个请求前都去检查本地时间。
还有一个容易被忽略的细节:Authorization头里携带Bearer令牌时,如果前端代码通过模板字符串拼接用户输入,理论上可能引入换行符导致请求头注入。虽然现代浏览器对请求头做了限制,但在封装请求工具时仍应避免直接拼接任何外部变量到头部,统一使用请求库提供的配置对象。
接口鉴权与越权防护的落点前后端分离后,接口数量通常比传统MVC架构多出数倍,因为每个页面组件都可能独立请求数据。接口一多,开发人员容易在“这个接口只有管理员页面会调用”的假设下省略服务端权限校验。攻击者根本不关心前端页面长什么样,直接重放接口请求就能试探出哪些接口缺少鉴权。因此所有接口都必须默认拒绝访问,只有显式声明了权限规则的接口才允许放行。
水平越权是另一个高频问题。前端传递资源ID,后端只校验用户是否登录,却不校验该资源是否属于当前用户。比如订单详情接口/api/orders/{id},攻击者遍历ID就能拉取其他用户的订单。解决这个问题需要在服务端建立资源归属关系校验,而不是依赖前端隐藏按钮或禁用下拉选项。具体做法是在每个需要资源级权限的接口中,根据当前登录用户身份查询资源归属,不匹配则返回404而非403,避免泄露资源是否存在的信息。
对于复杂角色系统,建议在网关层做粗粒度校验,在服务层做细粒度校验。网关层判断用户是否具备访问该路径前缀的角色,服务层判断用户是否具备操作该具体资源的能力。两层之间通过请求上下文传递用户身份,避免每个服务重复解析令牌。
前端输入校验与服务端二次校验的配合很多团队认为前端已经做了表单校验,服务端可以适当放宽。这种想法在分离架构下尤其危险,因为攻击者可以绕过前端直接构造请求。服务端必须对所有输入进行独立校验,包括类型、长度、格式、取值范围。前端校验只是用户体验优化,不是安全边界。
针对JSON请求体的校验,服务端需要明确拒绝未知字段。如果接口只接受username和password两个字段,请求体中多出来的isAdmin字段应当被丢弃或直接报错,而不是被反序列化到对象后进入业务逻辑。很多框架默认会忽略未知字段,这给了攻击者尝试注入额外参数的机会。建议在全局配置中开启严格模式,对未知字段返回400错误。
数值类型的边界也要注意。前端传过来的用户ID可能是字符串,服务端如果直接用于数据库查询,需要先转换为整数并判断范围。对于数组类型的参数,要限制最大元素数量,防止攻击者传入超大数组导致服务端资源耗尽。
XSS防护在分离架构中的特殊处理前后端分离后,前端框架默认会对插值表达式中的内容进行转义,这降低了一部分XSS风险。但v-html、dangerouslySetInnerHTML这类API仍然可以绕过转义,直接把字符串当作HTML渲染。凡是使用这类API的地方,必须对内容进行白名单过滤,而不是简单的正则替换。
更隐蔽的XSS来源是富文本编辑器。很多项目允许用户提交HTML内容,前端直接渲染。攻击者可以在富文本中插入事件处理器或javascript:协议的链接。处理富文本需要使用专门的服务端过滤库,基于白名单标签和属性进行清洗,并且禁止所有事件处理器属性。清洗后的内容再返回给前端渲染。
此外,前端路由跳转时如果使用了用户可控的参数作为跳转目标,需要校验目标地址是否属于站内路径。比如登录后重定向参数redirect=/dashboard是安全的,但redirect=javascript:alert(1)就可能触发XSS。处理方式是只允许以/开头的相对路径,并且拒绝包含协议头的绝对地址。
文件上传与静态资源的安全边界前后端分离项目中,文件上传接口往往独立于页面,攻击者更容易自动化测试上传漏洞。文件类型校验不能只依赖前端扩展名,也不能只依赖Content-Type请求头,这两个都可以伪造。服务端需要读取文件头部的魔数来判断真实类型,并且对图片文件进行重编码,去除可能嵌入的脚本内容。
上传后的文件存储位置要避免放在可执行目录下。如果使用云存储,需要设置对象为私有读,通过服务端生成短期访问URL返回给前端,而不是直接暴露公开读地址。对于用户上传的SVG文件要格外谨慎,因为SVG可以包含脚本,直接在前端以img标签加载是安全的,但如果允许用户通过object或iframe嵌入,就可能执行脚本。建议对SVG做白名单标签过滤或直接禁止上传。
下载接口也要防止路径穿越。如果前端传递文件名,服务端拼接路径时需要使用规范化函数处理,确保最终路径仍然在允许的目录范围内。攻击者可能传入../../etc/passwd这样的路径,如果服务端不做规范化校验,就会读取到敏感文件。
CORS配置的精细化控制前后端分离部署时,前端域名和后端API域名通常不同,需要配置CORS允许跨域请求。但很多项目图省事,直接设置Access-Control-Allow-Origin: *,同时允许所有请求头和所有方法。这样等于把API开放给任何网站,攻击者可以在恶意页面中诱导已登录用户发起跨域请求。
正确的做法是明确列出允许的前端域名,并且根据接口需求限制允许的请求方法。对于需要携带凭证的请求,Access-Control-Allow-Origin不能为*,必须指定具体域名,同时设置Access-Control-Allow-Credentials: true。预检请求的缓存时间可以适当缩短,避免配置变更后客户端仍然使用旧的缓存策略。
另外,CORS只影响浏览器端的跨域限制,不影响服务端之间的直接调用。攻击者可以用curl等工具直接请求API,所以CORS不能替代服务端鉴权。它只是防止浏览器端的跨域滥用,真正的安全边界仍然在服务端。
日志与监控的实战价值前后端分离架构下,攻击者可以直接对API发起大量自动化请求,日志是发现攻击行为的第一手资料。但很多项目的日志只记录了请求路径和状态码,缺少用户身份、请求参数、响应时间等关键信息。建议在网关层统一记录每次请求的用户ID、IP、User-Agent、请求方法、路径、状态码和耗时,对于非200响应记录请求体摘要。
针对认证失败、权限拒绝、参数校验失败等事件,需要设置告警阈值。比如同一用户在一分钟内出现五次权限拒绝,可能是攻击者在尝试越权访问,应当触发告警并临时限制该用户的请求频率。日志中要避免记录敏感字段,比如密码、令牌、身份证号等,防止日志泄露造成二次伤害。
监控面板上需要关注接口的异常流量模式,比如某个接口的请求量突然暴增、某个用户频繁请求不同资源ID、大量404响应集中出现。这些模式往往预示着攻击行为,及时响应可以阻止攻击扩大。
前后端分离的安全防护难点不在于技术本身,而在于职责边界的重新划分。前端负责用户体验和安全提示,服务端负责真正的安全校验和数据过滤。任何把安全责任推给前端的做法,最终都会在接口层被攻击者利用。把凭证管理、接口鉴权、输入校验、输出过滤、日志监控这五个环节做实,比堆砌安全设备更有效。
