Angular9 防范跨站脚本(XSS)攻击
跨站脚本(XSS)允许攻击者将恶意代码注入到页面中。这些代码可以偷取用户数据 (特别是它们的登录数据),还可以冒充用户执行操作。它是 Web 上最常见的攻击方式之一。
为了防范 XSS 攻击,你必须阻止恶意代码进入 DOM。比如,如果某个攻击者能骗你把 <script>
标签插入到 DOM,就可以在你的网站上运行任何代码。 除了 <script>
,攻击者还可以使用很多 DOM 元素和属性来执行代码,比如 <img onerror="...">
、<a href="javascript:...">
。 如果攻击者所控制的数据混进了 DOM,就会导致安全漏洞。
Angular 的“跨站脚本安全模型”
为了系统性的防范 XSS 问题,Angular 默认把所有值都当做不可信任的。 当值从模板中以属性(Property
)、DOM 元素属性(Attribte
)、CSS 类绑定或插值等途径插入到 DOM 中的时候, Angular 将对这些值进行无害化处理(Sanitize
),对不可信的值进行编码。
Angular 的模板同样是可执行的:模板中的 HTML、Attribute 和绑定表达式(还没有绑定到值的时候)会被当做可信任的。 这意味着应用必须防止把可能被攻击者控制的值直接编入模板的源码中。永远不要根据用户的输入和原始模板动态生成模板源码! 使用离线模板编译器是防范这类“模板注入”漏洞的有效途径。
无害化处理与安全环境
无害化处理会审查不可信的值,并将它们转换成可以安全插入到 DOM 的形式。多数情况下,这些值并不会在处理过程中发生任何变化。 无害化处理的方式取决于所在的环境:一个在 CSS 里面无害的值,可能在 URL 里很危险。
Angular 定义了四个安全环境 - HTML,样式,URL,和资源 URL:
- HTML:值需要被解释为 HTML 时使用,比如当绑定到
innerHTML
时。
- 样式:值需要作为 CSS 绑定到
style
属性时使用。
- URL:值需要被用作
URL
属性时使用,比如<a href>
。
- 资源
URL
的值需要作为代码进行加载并执行,比如<script src>
中的URL
。
Angular 会对前三项中种不可信的值进行无害化处理,但不能对第四种资源 URL
进行无害化,因为它们可能包含任何代码。在开发模式下, 如果在进行无害化处理时需要被迫改变一个值,Angular 就会在控制台上输出一个警告。
无害化示例
下面的例子绑定了 htmlSnippet 的值,一次把它放进插值里,另一次把它绑定到元素的 innerHTML
属性上。
Path:"src/app/inner-html-binding.component.html" 。
<h3>Binding innerHTML</h3>
<p>Bound value:</p>
<p class="e2e-inner-html-interpolated">{{htmlSnippet}}</p>
<p>Result of binding to innerHTML:</p>
<p class="e2e-inner-html-bound" [innerHTML]="htmlSnippet"></p>
插值的内容总会被编码 - 其中的 HTML 不会被解释,所以浏览器会在元素的文本内容中显示尖括号。
如果希望这段 HTML 被正常解释,就必须绑定到一个 HTML 属性上,比如 innerHTML
。但是如果把一个可能被攻击者控制的值绑定到 innerHTML
就会导致 XSS 漏洞。 比如,包含在 <script>
标签的代码就会被执行:
Path:"src/app/inner-html-binding.component.ts (class)" 。
export class InnerHtmlBindingComponent {
// For example, a user/attacker-controlled value from a URL.
htmlSnippet = 'Template <script>alert("0wned")</script> <b>Syntax</b>';
}
Angular 认为这些值是不安全的,并自动进行无害化处理。它会移除 <script>
标签,但保留安全的内容,比如该片段中的 <b>
元素。
避免直接使用 DOM API
浏览器内置的 DOM API 不会自动保护你免受安全漏洞的侵害。比如 document
、通过 ElementRef
拿到的节点和很多第三方 API,都可能包含不安全的方法。如果你使用能操纵 DOM 的其它库,也同样无法借助像 Angular 插值那样的自动清理功能。 所以,要避免直接和 DOM 打交道,而是尽可能使用 Angular 模板。
浏览器内置的 DOM API 不会自动针对安全漏洞进行防护。比如,document
(它可以通过 ElementRef
访问)以及其它第三方 API 都可能包含不安全的方法。 要避免直接与 DOM 交互,只要可能,就尽量使用 Angular 模板。
内容安全策略
内容安全策略(CSP) 是用来防范 XSS 的纵深防御技术。 要打开 CSP,请配置你的 Web 服务器,让它返回合适的 HTTP 头 Content_Security_Policy
。 要了解关于内容安全策略的更多信息,请参阅 HTML5Rocks 上的内容安全策略简介。
使用离线模板编译器
离线模板编译器阻止了一整套被称为“模板注入”的漏洞,并能显著增强应用程序的性能。尽量在产品发布时使用离线模板编译器, 而不要动态生成模板(比如在代码中拼接字符串生成模板)。由于 Angular 会信任模板本身的代码,所以,动态生成的模板 —— 特别是包含用户数据的模板 —— 会绕过 Angular 自带的保护机制。 要了解如何用安全的方式动态创建表单,请参见 构建动态表单 一章。
服务器端 XSS 保护
服务器端构造的 HTML 很容易受到注入攻击。当需要在服务器端生成 HTML 时(比如 Angular 应用的初始页面), 务必使用一个能够自动进行无害化处理以防范 XSS 漏洞的后端模板语言。不要在服务器端使用模板语言生成 Angular 模板, 这样会带来很高的 “模板注入” 风险。
更多建议: