AngularJS 作为一款经典的前端框架,其双向数据绑定和动态模板渲染特性为开发者提供了极大的便利,这些特性在处理用户输入时若缺乏安全防护,极易引发跨站脚本攻击(XSS),本文将通过具体示例详解 AngularJS 用户输入动态模板中的 XSS 攻击原理、攻击场景及防御措施,帮助开发者构建更安全的应用。

AngularJS 动态模板与 XSS 的关联性
AngularJS 的模板引擎通过 $sanitize 服务和 ng-bind、ng-bind-html 等指令实现数据渲染,当直接使用用户输入拼接模板或使用 ng-bind-html 渲染未过滤的 HTML 字符串时,恶意脚本可能被注入并执行,若用户输入 <script>alert('XSS')</script>,且该输入被直接插入 DOM,浏览器会自动执行其中的脚本代码,导致安全风险。
XSS 攻击示例详解
基础场景:ng-bind-html 未过滤
假设有一个评论功能,允许用户输入 HTML 内容,开发者直接使用 ng-bind-html 渲染:
<div ng-controller="CommentController"> <div ng-bind-html="userComment"></div> </div>
对应的控制器:
app.controller('CommentController', function($scope) {
$scope.userComment = '<img src="x" onerror="alert(\'XSS Attack!\')">'; // 恶意输入
});
攻击效果:页面加载后会弹出提示框,恶意脚本成功执行,攻击者可通过 onerror、onclick 等事件属性或 <script> 标签注入任意 JavaScript 代码。
动态拼接模板:ng-include 与用户输入
若使用 ng-include 动态加载模板,且模板路径来自用户输入:
<div ng-controller="TemplateController"> <div ng-include="userTemplateUrl"></div> </div>
控制器:

app.controller('TemplateController', function($scope) {
$scope.userTemplateUrl = 'malicious.html'; // 恶意模板路径
});
攻击效果:若 malicious.html 内容为 <script>alert('XSS via ng-include')</script>,加载后脚本即执行,攻击者可托管恶意模板,诱导用户加载并执行恶意代码。
表单输入与表达式注入
在表单中,若用户输入被直接用于 AngularJS 表达式:
<div ng-controller="FormController">
<input ng-model="userInput" type="text">
<div>{{userInput}}</div>
</div>
攻击者输入 {{constructor('alert(1)')()}},攻击效果:AngularJS 会解析表达式并执行,导致代码执行,这是 AngularJS 表达式沙箱漏洞的典型利用方式(注:AngularJS 1.6+ 已移除表达式沙箱,但仍需警惕)。
攻击原理与风险分析
攻击原理
AngularJS 的动态模板渲染依赖 $compile 服务,该服务会解析模板中的指令和表达式,并将数据绑定到 DOM,当用户输入包含恶意 HTML 或 JavaScript 时,若未经过滤,$compile 会将其直接渲染为 DOM 节点,浏览器内核会自动执行其中的脚本。
风险场景
| 场景 | 风险描述 |
|---|---|
| 用户评论/私信 | 恶意脚本窃取用户 Cookie、会话信息,或执行任意操作(如转账、删除数据)。 |
| 动态表单生成 | 攻击者通过表单输入构造恶意表达式,获取应用敏感数据或控制用户浏览器。 |
防御措施与最佳实践
使用 $sanitize 服务过滤 HTML
AngularJS 提供 $sanitize 服务(需引入 ngSanitize 模块),可移除 HTML 中的危险标签和属性:
app.controller('CommentController', function($scope, $sanitize) {
$scope.userComment = $sanitize('<img src="x" onerror="alert(\'XSS\')">'); // 过滤后仅保留安全标签
});
效果:onerror 等危险属性会被移除,仅允许安全的 HTML 标签和属性。

限制 ng-bind-html 的使用范围
避免对用户输入直接使用 ng-bind-html,仅对可信内容(如管理员编辑的富文本)使用,并结合白名单过滤:
<div ng-bind-html="trustedComment | toTrusted"></div>
app.filter('toTrusted', function($sce) {
return function(text) {
return $sce.trustAsHtml(text); // 通过 $sce 标记为可信内容
};
});
禁用表达式动态解析
对于不受信任的用户输入,使用 ng-bind 代替 ,避免 AngularJS 表达式解析:
<input ng-model="userInput" type="text"> <div ng-bind="userInput"></div> <!-- 安全:不解析表达式 -->
输入验证与输出编码
- 输入验证:通过正则表达式限制用户输入格式(如禁止
<script>标签)。 - 输出编码:对动态内容进行 HTML 实体编码(如
<转换为<),但需注意 AngularJS 的$sanitize已内置此功能。
升级 AngularJS 版本
AngularJS 1.6+ 移除了表达式沙箱,修复了部分 XSS 漏洞,建议升级至最新稳定版本,并启用 $sce(严格上下文转义)服务:
app.config(function($sceProvider) {
$sceProvider.enabled(false); // 生产环境建议启用,强制严格转义
});
AngularJS 的动态模板特性虽提升了开发效率,但也为 XSS 攻击提供了可乘之机,开发者需始终遵循“不信任用户输入”的原则,通过 $sanitize、$sce 等工具过滤内容,限制动态模板的使用范围,并结合输入验证与输出编码构建多层防御,只有将安全意识融入开发全流程,才能有效降低 XSS 风险,保障应用与用户数据的安全。