Angular HTTP 安全防护:深入理解 XSRF/CSRF 与 XSSI 的内置机制与实战配置
Angular HTTP 安全防护:深入理解 XSRF/CSRF 与 XSSI 的内置机制与实战配置
导读
本指南聚焦 Angular 框架针对两类高危 HTTP 漏洞——跨站请求伪造(Cross-Site Request Forgery,简称 CSRF/XSRF)与跨站脚本包含(Cross-Site Script Inclusion,简称 XSSI)——提供的内置防护机制。文章将阐明这两类攻击的成因与攻击路径,说明「服务端必须承担主要防护、Angular 在客户端侧提供集成辅助」的职责边界,并给出基于 HttpClient 的可落地配置方案。读完本文,你将能识别自己项目中 XSRF/XSSI 的风险点,正确配置 Angular 的 token 传递与响应前缀剥离机制,并与后端协作形成完整的防护闭环。
两类 HTTP 漏洞:同属浏览器信任边界问题
Angular 官方安全实践(见仓库 security 主题文档)明确列出了框架内置防护的两类常见 HTTP 漏洞:跨站请求伪造(CSRF/XSRF) 与 跨站脚本包含(XSSI)。这两者与经典的跨站脚本(XSS)攻击不同:
- XSS 是向受害页面注入恶意脚本,利用的是页面渲染逻辑对「内容」的信任;
- XSRF 是借用受害者的已认证会话,让浏览器替攻击者发送伪造请求,利用的是服务器对「请求来源」的信任;
- XSSI 则是通过
<script>标签跨域读取 JSON 接口数据,利用的是脚本标签不受同源策略限制的特性。
仓库中的 http-vulnerabilities 主题文档 给出的核心结论是:这两类漏洞都必须主要在服务端进行缓解,Angular 的作用是提供客户端侧的辅助集成能力,让前后端配合更加顺畅。 理解这一点至关重要——仅在前端启用防护而服务端不做校验,防护等于形同虚设。
一、XSRF/CSRF:攻击原理与 Angular 的内置对策
1.1 攻击如何发生
跨站请求伪造(XSRF/CSRF)是一种恶意利用方式:攻击者诱使受害者的浏览器向受害者已登录的受信站点发送未授权的请求(参见仓库 xsrf-protection 主题文档)。
它与钓鱼(Phishing)有本质区别:
- 钓鱼攻击试图窃取凭证(用户名、密码),攻击者需要拿到登录信息;
- XSRF 攻击不窃取任何凭证,它直接利用受害者浏览器中仍处于有效状态的会话(Cookie 或 Session),以受害者的身份执行恶意操作。
其攻击链条(详见仓库 cross-site-request-forgery 主题文档)可以概括为三步:
- 会话自动携带:浏览器在向某个域名发送请求时,会自动附带该域名的会话 Cookie——这正是浏览器维持登录态的机制,也恰是漏洞的根源;
- 伪造请求发出:受害者在已登录应用 A 的情况下,访问了恶意站点 B;站点 B 页面中的隐藏脚本(如表单自动提交、隐藏的
<img>/<script>标签)向站点 A 发起请求; - 服务端误判:由于请求携带了合法的会话 Cookie,服务器将这些请求当作受害者的真实操作加以执行,例如转账、改密、删除数据等,用户数据与账户完整性因此被破坏。
从本质上看,XSRF 利用了**「浏览器无法区分当前请求是由用户本人发起,还是由恶意页面代为发起」**这一信任缺口,绕过了应用的预期校验步骤。
1.2 为什么主要防线必须落在服务端
XSRF 的攻击面在服务端,因为服务器才是最终执行「改变状态」操作的一方。仅靠前端代码无法阻止恶意站点构造请求——恶意脚本根本不经过你的 Angular 应用,它直接在受害者的浏览器里向你的后端地址发请求。因此:
- 服务端必须校验:所有涉及状态变更的请求(POST/PUT/PATCH/DELETE)都应验证请求中携带的 CSRF Token、自定义请求头、Origin/Referer 等来源信号;
- 前端只做辅助:Angular 的帮助在于——让合法请求能够自动、可靠地携带服务端需要的 Token,从而与服务端的校验逻辑对接,避免开发者在每个请求里手动处理。
1.3 Angular 客户端的 XSRF 防护机制
Angular 的 HttpClient(定义于 @angular/common/http,参见仓库 http-client 主题文档)内置了一套 XSRF 防护机制,采用业界常见的 Double Submit Cookie(双重提交 Cookie) 模式。
其工作流程(参见仓库 httpclient-csrf 主题文档)如下:
- 读取 Cookie 中的 Token:应用首次访问时,服务端在响应中通过 Cookie 下发一个安全令牌(Angular 默认约定的 Cookie 名为
XSRF-TOKEN); - 自动回填请求头:当应用后续发起请求时,
HttpClient会自动读取该 Cookie 的值,并将其写入自定义请求头(Angular 默认约定的请求头名为X-XSRF-TOKEN); - 服务端比对校验:服务器读取请求头中的 Token,与 Cookie 中的 Token 进行比对,从而确认「请求来自持有合法 Cookie 的同源应用页面」,而不是第三方恶意站点伪造的请求。
这里有一个关键点:恶意站点是无法读取受害者在目标域名下的 Cookie 的(受同源策略与 Cookie 的 SameSite/HttpOnly 等属性约束),因此它无法在伪造请求中正确构造 X-XSRF-TOKEN 请求头,服务端校验即可将其拦截。
在模块化(NgModule)写法中,HttpClientXsrfModule 负责启用并配置这套机制(官方 API 参见仓库 cross-site-request-forgery 主题文档 所列的 HttpClientXsrfModule 链接)。默认配置下无需额外声明即可生效,也可以通过 withOptions 自定义 Cookie 名与请求头名,以匹配后端的实际约定:
import { NgModule } from '@angular/core';
import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN', // 读取令牌的 Cookie 名,需与后端下发一致
headerName: 'X-XSRF-TOKEN', // 回填令牌的请求头名,需与后端校验一致
}),
],
})
export class AppModule {}
若项目使用现代的 provideHttpClient(Standalone/函数式配置)方式,可以通过 withXsrfConfiguration 传入同样的两个参数,效果一致:
import { provideHttpClient, withXsrfConfiguration } from '@angular/common/http';
export const appConfig = {
providers: [
provideHttpClient(
withXsrfConfiguration({
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN',
})
),
],
};
配置要点说明:
| 配置项 | 作用 | 注意事项 |
|---|---|---|
cookieName |
指定从哪个 Cookie 读取令牌 | 必须与后端写入的 Cookie 名称完全一致,大小写敏感 |
headerName |
指定写入哪个请求头 | 必须与后端校验的请求头名称完全一致 |
| 默认值 | XSRF-TOKEN / X-XSRF-TOKEN |
两端都遵循默认约定时可以不传任何配置 |
1.4 服务端配合清单(职责边界)
Angular 只负责「客户端自动携带 Token」,真正的安全边界在后端。与后端协作时,至少需要确认以下事项:
- 登录成功后下发 Token:服务端需在用户会话中生成随机 Token,并通过
Set-Cookie下发(建议同时考虑SameSite属性与Secure标志); - 状态变更请求必须校验:所有 POST/PUT/PATCH/DELETE 请求都校验
X-XSRF-TOKEN请求头与 Cookie 中的 Token 是否一致,不一致即拒绝; - CSRF Token 不应随同源请求之外的渠道泄露:Token 通过 Cookie 下发而非 URL 参数,避免被 Referer 或日志泄漏;
- 敏感操作可叠加校验:对转账、改密等高危操作,可在 XSRF 防护之外叠加二次验证(如 OTP、图形验证码)。
二、XSSI:JSON 漏洞与响应前缀剥离
2.1 攻击原理:借 <script> 标签读取跨域 JSON
跨站脚本包含(XSSI)也被称为 JSON 漏洞(JSON Vulnerability)。它可以让攻击者的网站读取来自某 JSON API 的数据(参见仓库 cross-site-script-inclusion 主题文档)。
攻击思路利用了浏览器两条基础特性:
<script>标签不受同源策略限制——页面可以通过<script src="https://api.example.com/user">的方式加载任意域下的脚本资源;- 旧式浏览器允许覆盖内置 JavaScript 对象构造函数——攻击者可以在自己页面里先改写
Array、Object等构造器,再通过<script>标签引入目标 JSON 接口。
攻击流程如下:
- 受害者的浏览器在访问恶意站点时,该站点通过
<script>标签请求受害者已登录的 JSON API(请求同样会自动携带会话 Cookie,返回的是敏感数据); - 由于响应内容以 JavaScript 形式被「执行」,攻击者预先改写的构造函数会在解析 JSON 数组/对象时被触发;
- 通过构造器钩子,攻击者的脚本得以收集、外传原本只该由目标应用读取的数据。
2.2 Angular 的内置对策:自动剥离危险前缀
针对这类攻击,服务端常见的缓解手段是在 JSON 响应体前附加一个无法被当作合法 JavaScript 执行的前缀,例如:
)]}',
{"id":1,"email":"user@example.com"}
浏览器解析这段响应时会因语法错误而拒绝执行(攻击者的 <script> 引入方式随之失效),而合法的前端应用则可以自行剥离前缀后再解析。
Angular 的 HttpClient 已内置识别这一业界约定:在进一步解析之前,自动从所有响应中剥离前缀 )]}',\n(参见仓库 cross-site-script-inclusion 主题文档)。也就是说:
- 服务端返回
)]}',\n+ JSON 的格式; - 前端开发者在
HttpClient中无需编写任何剥离代码,拿到的是干净的 JSON 数据; - 攻击者通过
<script>标签引入时,响应以)]}'开头而无法作为脚本执行。
配合 making-requests 主题文档 所述的使用方式——HttpClient 的各 HTTP 方法返回 RxJS Observable,订阅后发出请求并在服务端响应时发射结果——一个典型的安全调用代码如下:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) {}
getProfile() {
// 服务端响应形如:)]}',\n{"id":1,"name":"Alice"}
// HttpClient 自动剥离前缀,这里拿到纯 JSON 对象
return this.http.get<{ id: number; name: string }>('/api/profile');
}
}
需要说明的是,XSSI 前缀剥离属于约定驱动的被动防护:Angular 默认对所有响应执行剥离逻辑,但响应是否带前缀、Token 校验是否生效,仍取决于服务端是否按约定实现。服务端才是决定「数据是否会被跨域读取」的第一道闸门。
三、与 XSS 的区别:Angular 更广泛的安全姿态
虽然本指南聚焦 CSRF/XSRF 与 XSSI,但理解 Angular 整体安全模型有助于正确归类风险。跨站脚本(XSS)允许攻击者向网页注入恶意代码,进而窃取用户数据与登录信息,甚至冒充用户执行操作——这是十余年来最严重的 Web 漏洞之一(参见仓库 cross-site-scripting 主题文档)。
Angular 对 XSS 的策略是「默认不信任所有值」:当值通过模板绑定或插值插入 DOM 时,Angular 会自动对不可信值进行清理(Sanitize)与转义。这与 XSRF/XSSI 的防护思路不同:
| 漏洞 | 攻击目标 | Angular 内置对策 | 主要防线 |
|---|---|---|---|
| XSS(跨站脚本) | 向页面注入并执行恶意脚本 | 模板绑定/插值的自动清理与转义 | 客户端框架 + 内容策略 |
| XSRF/CSRF(跨站请求伪造) | 借用受害者会话代发请求 | Cookie Token → 请求头自动回填 | 服务端校验为主 |
| XSSI(跨站脚本包含) | 借 <script> 标签跨域读 JSON |
自动剥离 )]}',\n 响应前缀 |
服务端加前缀为主 |
三者的共同点在于:框架提供的都是「默认开启的辅助机制」,最终的安全边界都需要服务端落实。
四、实战自查清单与总结
在 Angular 项目中落实 HTTP 漏洞防护,建议按以下清单逐项核对:
- 确认后端已做主要防护:CSRF 校验、XSSI 前缀、认证授权均以服务端为准,前端机制不能替代;
- 保持 Cookie/Header 命名一致:核对后端下发的 Cookie 名与
HttpClientXsrfModule.withOptions/withXsrfConfiguration中的cookieName、headerName是否完全匹配; - 确认状态变更请求默认携带 Token:
HttpClient的 XSRF 拦截器默认工作,若自定义了HttpInterceptor或绕过了HttpClient(如直接用fetch),需自行实现 Token 回填; - 确认服务端响应带 XSSI 前缀:若 JSON 接口涉及敏感数据且希望抵御旧浏览器下的 XSSI,服务端应返回
)]}',\n前缀,HttpClient会自动剥离; - 审视高危操作:转账、改密、删除等敏感操作,建议在 XSRF 之上叠加额外验证。
核心结论:Angular 通过 HttpClient 为开发者内置了两套开箱即用的 HTTP 漏洞辅助防护——XSRF 采用「Cookie 中的 Token 自动回填到自定义请求头」的双重提交模式,XSSI 采用「自动剥离 )]}',\n 响应前缀」的约定模式。二者都遵循同一原则:服务端必须承担主要缓解责任,Angular 让客户端侧的集成更安全、更省心。将框架的默认机制与后端的严格校验结合起来,才能为 Angular 应用建立完整的 HTTP 安全防线。