CSRF(Cross-Site Request Forgery),中文名称:跨站请求伪造攻击。
CSRF原理就是攻击者想方设法让你访问某一条链接,如果你真的访问了这一条链接,你就会执行攻击者想让你执行的操作了,简而言之,就是你如果访问了攻击者的链接,你就会被攻击。
用户的操作其实是通过访问具体的URL从而让服务端去识别用户的操作然后去执行特定的脚本。
有一个博客网站的地址是 http://www.123.com,然后这个网站有一个URL是 http://www.123.com/delete.php,这个URL是通过接收get方式提交过来的数据从而删除文章的。
有一天,你登录了这个网站并把这个网站的COOKIE设置保存30天,接着你删除ID为1的文章,脚本就会访问 http://www.123.com/delete.php?id=1 这个URL,服务器会接收到你的请求,识别你的身份(通过获取你登录时留在客服端的COOKIE从而验证你的身份)和URL参数以及参数的值(URL里的问号后面部分就是参数和参数值,这里的参数是id,参数值是1),如果身份和参数值都符合预设的条件就执行删除指令,如果执行成功,这篇id等于1的文章就会被删除。如果你删除id为2的文章,脚本就会访问http://www.123.com/delete.php?id=2 这个URL,后续过程和上面的后续过程一模一样,只是传给服务器的参数变了而已。
在这30天内,你点开了一个 URL 为 http://www.123.com/delete.php?id=3 的链接,接着你发现你博客里有一篇id等于3的文章不见了,你这时候拼命思考,为什么这篇文章会不见了呢?是系统出问题了还是我自己删除但是却忘记了呢?其实就是你访问 http://www.123.com/delete.php?id=3 这个URL时删除的,你执行了你不想执行的操作。
这个例子的后果不是很严重,但如果是这是一个转账的网站呢?你转账1000元给id等于1的人,访问的是 http://www.123.com/transaction.php?id=1&amount=1000,如果你不小心访问了一个URL 为 http://www.123.com/transaction.php?id=3&amount=1000的链接,你的1000元就会从你口袋飞走了,而且你还不知道它飞走了。
所以当你访问一些URL的时候,其实是有风险的,这锅是你要背吗?是要怪你乱点链接吗?肯定不是你,链接在上网过程中随处可见,比如一段文字可以是链接,一张图片可以是链接,甚至一大块DOM元素都可以是链接,谁叫a标签可以在很多DOM元素上套呢,更甚至在一些网站上都不用你点击链接,网站会自动帮你访问链接,所以谁能事先知道浏览某个网站是有危险的或者访问某个链接是有风险的呢?要背锅的应该是某些网站的程序员,比如这个例子中 http://www.123.com 这个网站的程序员,因为他们没做好CSRF的防御。
从上面可以看出,实现CSRF的条件有以下几方面
常见的CSRF攻击主要有两种类型,get类型和post类型。
get类型的CSRF是CSRF中最常见,危害最大,但也是最简单的一种类型了,只要一个http请求就可以了,这种类型又可以分为手动型和自动型,手动型就是需要我们自己去点击才会发生攻击,比如各种URL链接,各种a标签包裹的DOM元素。自动型的是不需要我们点击,只要当我们访问具有某些标签的网站的时候就会自动发生攻击,比如网页中有
因为这些标签需要访问指定的URL才能发挥作用,所以会发送http请求,又因为这些标签是网页加载的时候就会自动发送http请求,所以当网页加载的时候CSRF就会自动发生。要实现这种CSRF就必须实现跨域访问,比如利用上面这两个可以发送跨域请求的标签,AJAX是不能实现这种CSRF的,因为AJAX有同源策略,当使用AJAX的时候,接受数据的URL地址的域名、端口、协议、必须和当前地址的域名、端口、协议都一致才能成功发送数据,不然数据是发送不成功的。
post请求和get请求是不同的,post请求是要把参数放在http的请求body里发送给服务器,所以post类型的CSRF需要用post的方式发送请求。我们常用的post请求方式一般就两个,AJAX和表单,当正如我上面所说,AJAX是有同源策略的,所以不能用AJAX的方式发送post请求,所以就剩下表单的方式了,没错,表单是支持跨域发送请求的。通常的方法就是创建一个自动提交的表单,比如
静态创建一个自动提交的表单
动态创建一个自动提交的表单
当用户浏览有这样表单的网页就会自动发生CSRF。
http协议的请求头里有一个Referer的字段,这个字段是用来识别http请求是从哪个网站发起的,比如有一个网页的地址是http://www.123.com,然后里面有个img标签,如下
这是一个请求另外一个网站某张图片的img标签,这个图片的请求头里面的Referer字段就会等于http://www.123.com,这样另外一个网站的服务器接受到请求的时候,如果验证这个请求的Referer字段,就能发现这个请求是 http://www.123.com 这个网页里发起的,利用这样的方法,如果在假冒网站里发送正牌网站的请求,正牌网站的服务器能检测到这个请求不是从自己网站里发送出来的,从而拒绝执行请求,CSRF就失败了。
这种方法比较简单,只是在执行请求前加多几行验证Referer字段的代码而已,但是,这种方法其实对CSRF就只有一点用处而已,为什么这么说呢?
首先Referer字段其实是浏览器提供的,所以如果浏览器有漏洞的话,完全可以篡改Referer字段,而且现在浏览器好像为了保护用户隐私而提供了禁止记录Referer字段的功能,这样如果用验证Referer的方法会把用户所有的请求都拒绝掉的,
其次并不是所以的请求的请求头里的都会有Referer字段的,比如在浏览器地址栏中输入URL地址直接访问就不会有Referer字段。
下面的几种情况的http请求的请求头里都是没有Referer字段的。
下面几种情况是有Referer字段的
post类型的CSRF一般都是经过表单发送的,所以说所以说验证Referer可以有效的防范post类型的CSRF,但是总的来说验证 Referer 并不是对CSRF十分有效的防范方法。
原理就是每当用户打正牌开网站的时候,正牌网站会自动生成一个随机的字符串,我们把这个字符串叫token好了,并把这个token保存在服务器里,然后把token添加到指定的地方,这个指定的地方可以是a标签的herf属性里,或者form标签的action属性里,也可以是ajax对象的data属性里,如果是a标签的herf属性里,只能添加到指定ID或者class的a标签的herf属性里,如果事先没有为指定的a标签添加指定的ID或者class属性,则需要要检测a标签的herf属性是不是以正牌网站的域名开头,如果是以正牌网站域名开头,则在这个a标签的herf属性里添加token参数,如果不这么做,在所有的a标签的herf属性里都添加token参数的话,则意味着所有网站的服务器都能接受到这个token参数,包括攻击者的服务器,这样token就泄漏了。正牌网站服务器把接收到的token参数与服务器保存的token参数作对比,如果一致则执行,不一致则拒绝执行。攻击者实现CSRF的前提之一就是必须知道正确的URL并诱导用户去访问这条URL,如果token不泄露,攻击者是不知道正确的URL的,所以就可以有效的防范CSRF了。这种方法的缺点就是token也许会泄露,如果token被攻击者得到,CSRF依旧可以发生。
这种方法和上面一种方法差不多,也是当用户访问网站的时候生成一个随机的字符串(token)保存在服务器里并添加到指定的地方,这次指定的地方不是URL参数了,而是把token添加到HTTP请求头里当自定义属性,这样服务器接收请求的时候验证请求头信息,如果发送请求头里的token和服务器保存的token一致才执行,不一致则拒绝执行,这种方法的缺点就是因为要设置请求头,所以要用到XMLHttpRequest这个类,所以所有的请求都必须用ajax发起。
,