Xss

什么是xss攻击
XSS攻击全称跨站脚本攻击(Cross-site scripting),是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。
如果web应用程序没有部署足够的安全验证,那么,这些攻击很容易成功。浏览器无法探测到这些恶意脚本是不可信的,所以,这些脚本可以任意读取cookie,session tokens,或者其它敏感的网站信息,或者让恶意脚本重写html内容。
在以下2种情况下,容易发生xss攻击:1)数据从一个不可靠的链接进入到一个web应用程序。2)没有过滤掉恶意代码的动态内容被发送给web用户。
恶意内容一般包括javascript,但是,有时候也会包括html,flash。XSS攻击的形式千差万别,但是,它们的共同点为:将一些隐私数据像cookie、session发送给攻击者,将受害者重定向到一个由攻击者控制的网站,在受害者的机器上进行一些恶意操作。
XSS攻击可以分为3类:存储型(持久型)、反射型(非持久型)、基于DOM。
Xss攻击分类
1.反射型xss
发出请求时,XSS代码出现在URL中,作为输入提交到服务器端,服务器端解析后响应,XSS代码随响应内容一起传回给浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,故叫反射型XSS。
一个简单的例子:
http://www.a.com/xss/reflect.php 的代码如下:
1 |
|
如果输入x的值未经任何过滤就直接输出,提交:1
http://www.foo.com/xss/reflect.php?x=<script>alert(1)</script>
则alert()函数会在浏览器触发。
2.存储型xss
存储型XSS和反射型XSS的差别仅在于,提交的代码会存储在服务器端(数据库,内存,文件系统等),下次请求目标页面时不用再提交XSS代码。如果页面显示不处理xss显示,则会被攻击。
最典型的例子是留言板XSS,用户提交一条包含XSS代码的留言存储到数据库,目标用户查看留言板时,那些留言的内容会从数据库查询出来并显示,浏览器发现有XSS代码,就当做正常的HTML与Js解析执行,于是触发了XSS攻击。
3.DOM xss
DOM—based XSS漏洞是基于文档对象模型Document Objeet Model,DOM)的一种漏洞。
DOM XSS和反射型XSS、存储型XSS的差别在于DOM XSS的代码并不需要服务器参与,触发XSS靠的是浏览器端的DOM解析,完全是客户端的事情。
http://www.a.com/xss/domxss.html 代码如下:
1 | eval(location.hash.substr(1)); |
触发方式为:http://www.a.com/xss/domxss.html#alert(1)
这个URL#后的内容是不会发送到服务器端的,仅仅在客户端被接收并解执行。
如何防御xss
1.过滤转义输入输出
2.避免使用eval,new Function等执行字符串的方法,除非确定字符串和用户输入无关。
3.使用innerHTML,document.write的时候,如果数据是用户输入的,那么需要对关键字符都进行过滤与转义。
4.对于非客户端cookie,比如保存用户凭证的session,务必标识为http only,这样js就获取不到这个cookie值了,安全性得到提高。
项目中XSS防御:
1.php输出:使用htmlspecialchars()函数。
htmlspecialchars() 函数把一些预定义的字符转换为 HTML 实体。
预定义的字符是:
1 | & (和号) 成为 & |
2.js中使用xss过滤:
1 | function $xss(str,type){ |
Sql注入
什么是sql注入
SQL注入就是一种通过操作输入来修改后台SQL语句达到代码执行进行攻击目的的技术。
SQL注入是一种将SQL代码添加到输入参数中,传递到服务器解析并执行的一种攻击手法。
SQL注入攻击是输入参数未经过滤,然后直接拼接到SQL语句当中解析,执行达到预想之外的一种行为,称之为SQL注入攻击。

Sql注入分类
1.数字注入
在浏览器地址栏输入:learn.me/sql/article.php?id=1,这是一个get型接口,发送这个请求相当于调用一个查询语句:
1 | $sql = "SELECT * FROM article WHERE id =",$id |
正常情况下,应该返回一个id=1的文章信息。那么,如果在浏览器地址栏输入:learn.me/sql/article.php?id=-1 OR 1 =1,这就是一个SQL注入攻击了,可能会返回所有文章的相关信息。为什么会这样呢?
这是因为,id = -1永远是false,1=1永远是true,所有整个where语句永远是ture,所以where条件相当于没有加where条件,那么查询的结果相当于整张表的内容
2.字符串注入
有这样一个用户登录场景:登录界面包括用户名和密码输入框,以及提交按钮。输入用户名和密码,提交。
这是一个post请求,登录时调用接口learn.me/sql/login.html,首先连接数据库,然后后台对post请求参数中携带的用户名、密码进行参数校验,即sql的查询过程。
假设正确的用户名和密码为user和pwd123,输入正确的用户名和密码、提交,相当于调用了以下的SQL语句:
SELECT * FROM user WHERE username = ‘user’ ADN password = ‘pwd123’
由于用户名和密码都是字符串,SQL注入方法即把参数携带的数据变成mysql中注释的字符串。mysql中有2种注释的方法:
1)’#’:’#’后所有的字符串都会被当成注释来处理
用户名输入:user’#(单引号闭合user左边的单引号),密码随意输入,如:111,然后点击提交按钮。等价于SQL语句:
1 | SELECT * FROM user WHERE username = 'user'#'ADN password = '111' |
‘#’后面都被注释掉了,相当于:
1 | SELECT * FROM user WHERE username = 'user' |
2)’– ‘ (–后面有个空格):’– ‘后面的字符串都会被当成注释来处理
用户名输入:user’– (注意–后面有个空格,单引号闭合user左边的单引号),密码随意输入,如:111,然后点击提交按钮。等价于SQL语句:
1 | SELECT * FROM user WHERE username = 'user'-- 'AND password = '111' |
‘– ‘后面都被注释掉了,相当于:
1 | SELECT * FROM user WHERE username = 'user' |
因此,以上两种情况可能输入一个错误的密码或者不输入密码就可登录用户名为’user’的账号,这是十分危险的事情。
如何预防SQL注入
1)严格检查输入变量的类型和格式
对于整数参数,加判断条件:不能为空、参数类型必须为数字
对于字符串参数,可以使用正则表达式进行过滤:如:必须为[0-9a-zA-Z]范围内的字符串
2)过滤和转义特殊字符
在username这个变量前进行转义,对’、”、\等特殊字符进行转义,如:php中的addslashes()函数对username参数进行转义
3)利用mysql的预编译机制
把sql语句的模板(变量采用占位符进行占位)发送给mysql服务器,mysql服务器对sql语句的模板进行编译,编译之后根据语句的优化分析对相应的索引进行优化,在最终绑定参数时把相应的参数传送给mysql服务器,直接进行执行,节省了sql查询时间,以及mysql服务器的资源,达到一次编译、多次执行的目的,除此之外,还可以防止SQL注入。具体是怎样防止SQL注入的呢?实际上当将绑定的参数传到mysql服务器,mysql服务器对参数进行编译,即填充到相应的占位符的过程中,做了转义操作。
项目中sql注入防御
1.限制变量类型:最好在获取参数时对参数类型进行校验,比如数字类型就 intval() 下。
2.项目中使用了CI框架,则尽量使用CI框架数据库内置查询构造器方法,里面已对参数字段进行了转义处理。如果自己拼写sql,php中则使用 mysql_real_escape_string 函数,或着 CI框架中可以使用 escape_str 函数过滤。
1 | database/DB_active_rec.php |



Csrf
什么是csrf
CSRF(Cross-site request forgery,中文为跨站请求伪造)是一种利用网站可信用户的权限去执行未授权的命令的一种恶意攻击。通过伪装可信用户的请求来利用信任该用户的网站,这种攻击方式虽然不是很流行,但是却难以防范,其危害也不比其他安全漏洞小。
简单点说,CSRF攻击就是攻击者利用受害者的身份,以受害者的名义发送恶意请求。与XSS(Cross-site scripting,跨站脚本攻击)不同的是,XSS的目的是获取用户的身份信息,攻击者窃取到的是用户的身份(session/cookie),而CSRF则是利用用户当前的身份去做一些未经过授权的操作。

CSRF的原理

从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:
1.登录受信任网站A,并在本地生成Cookie。
2.在不登出A的情况下,访问危险网站B。
看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:
1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了……)
3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
简单示例:
银行网站A,它以GET请求来完成银行转账的操作,如:http://www.mybank.com/Transfer.php?toBankId=11&money=1000
危险网站B,它里面有一段HTML的代码如下:
1 | <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000> |
首先,你登录了银行网站A,然后访问危险网站B,噢,这时你会发现你的银行账户少了1000块……
为什么会这样呢?
原因是银行网站A违反了HTTP规范,使用GET请求更新资源。
在访问危险网站B的之前,你已经登录了银行网站A,而B中的以GET的方式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),
所以你的浏览器会带上你的银行网站A的Cookie发出Get请求,去获取资源“http://www.mybank.com/Transfer.php?toBankId=11&money=1000”,
结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作……
CSRF攻击的对象与防范思路
我们要防范它,先要知道它的目标,然后设法保护这些目标。
我们要明白,仅仅靠发起CSRF攻击的话,黑客只能借助受害者的cookie骗取服务器的信任,但是黑客并不能凭借拿到cookie,也看不到 cookie的内容。另外,对于服务器返回的结果,由于浏览器同源策略的限制,黑客也无法进行解析。
这就告诉我们,我们要保护的对象是那些可以直接产生数据改变的服务,而对于读取数据的服务,则不需要进行CSRF的保护。
而保护的关键,是在请求中放入黑客所不能伪造的信息。
如何预防CSRF
1.最基本的手段:涉及敏感操作的请求改为POST请求
这个方法的确可以防范一些CSRF攻击,但是对于进阶攻击就无能为力了——POST请求一样可以伪造。
所以这个方法不够安全。只能提高攻击的门槛。
2.用户操作限制——验证码机制
方法:添加验证码来识别是不是用户主动去发起这个请求,由于一定强度的验证码机器无法识别,因此危险网站不能伪造一个完整的请求。
优点:简单粗暴,低成本,可靠,能防范99.99%的攻击者。
缺点:对用户不友好。
3.请求来源限制——验证 HTTP Referer 字段
方法:在HTTP请求头中有一个字段叫Referer,它记录了请求的来源地址。 服务器需要做的是验证这个来源地址是否合法,如果是来自一些不受信任的网站,则拒绝响应。
优点:零成本,简单易实现。
缺点:由于这个方法严重依赖浏览器自身,因此安全性全看浏览器。
兼容性不好:每个浏览器对于Referer的具体实现可能有差别。
并不一定可靠:在一些古老的垃圾浏览器中,Referer可以被篡改。
对用户不友好:Referer值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权。因此有些用户可能会开启浏览器防止跟踪功能,不提供Referer,从而导致正常用户请求被拒绝。
4.额外验证机制——token的使用
方法:使用token来代替验证码验证。由于黑客并不能拿到和看到cookie里的内容,所以无法伪造一个完整的请求。
基本思路如下:
服务器随机产生token(比如把cookie hash化生成),存在session中,放在cookie中或者以ajax的形式交给前端。
前端发请求的时候,解析cookie中的token,放到请求url里或者请求头中。
服务器验证token,由于黑客无法得到或者伪造token,所以能防范csrf
更进一步的加强手段(不需要session):
服务器随机产生token,然后以token为密钥散列生成一段密文
把token和密文都随cookie交给前端
前端发起请求时把密文和token都交给后端
后端对token和密文进行正向散列验证,看token能不能生成同样的密文
这样即使黑客拿到了token 也无法拿到密文。
优点:
安全性:极大地提高了破解成本(当然还是有办法破解),但是99%的攻击者看到散列的时候就已经望而生畏了。
易用性:非常容易实现。
友好性:对用户来说十分友好。
缺点:
性能担忧:需要hash计算,增加性能上的成本
cookie臃肿:更加依赖网络的情况
并不绝对安全:
一些论坛之类支持用户自己发表内容,由于系统也会在这个地址后面加上token,这样黑客可以在自己的网站上得到这个 token,并马上就可以发动CSRF攻击。(进一步加强法可以防范,或者验证链接是否是链到自己本站的,是就在后面添加 token,如果是通向外网则不加)
其他攻击方式如XSS攻击能拿到cookie和token,当然这不在本文的讨论范围之内。
对于POST请求,难以将token附在请求中。(可以通过框架和库解决)
5.曲线救国——在HTTP头中自定义属性并验证
方法:这种方法也是使用token并进行验证,和上一种方法不同的是把它放到HTTP头中自定义的属性里。
优点:
这样解决了上种方法在请求中加入 token 的不便
通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,安全性较高
缺点:
局限性非常大:XMLHttpRequest请求通常用于Ajax,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,造成不便。
对于旧网站,要把所有请求都改为XMLHttpRequest请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。
项目中csrf防御
Csrf主要预防在于服务端,目前项目中使用验证码和HTTP Referer等机制。前端需要做的主要是请求尽量都用post,提高攻击门槛。