CSRF的攻击与防范
CSRF 是什么?
Cross-site request forgery 跨站请求伪造,也被称为 “one click attack” 或者 session riding,通常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。CSRF 则通过伪装来自受信任用户的请求来利用受信任的网站。
CSRF 攻击类似 XSS 攻击,都是在页面中嵌入特殊部分引诱或强制用户操作从而得到破坏等的目的,区别就是迫使用户 访问特定 URL / 提交表单
还是执行 javascript 代码。
为什么叫 跨站请求
攻击?
从字面意思就可以理解:当你访问 fuck.com
黑客页面的时候,页面上放了一个按钮或者一个表单,URL/action 为http://you.com/delete-myself
,这样引导或迫使甚至伪造用户触发按钮或表单。
在浏览器发出 GET 或 POST 请求的时候,它会带上 you.com
的 cookie,如果网站没有做 CSRF 防御措施,那么这次请求在 you.com
看来会是完全合法的,这样就会对 you.com
的数据产生破坏。
CSRF 攻击的对象
在讨论如何抵御 CSRF 之前,先要明确 CSRF 攻击的对象,也就是要保护的对象。从以上的例子可知,CSRF
攻击是黑客借助受害者的 cookie 骗取服务器的信任,但是黑客并不能拿到 cookie,也看不到 cookie
的内容。另外,对于服务器返回的结果,由于浏览器同源策略的限制,黑客也无法进行解析。
因此,黑客无法从返回的结果中得到任何东西,他所能做的就是给服务器发送请求,以执行请求中所描述的命令,在服务器端直接改变数据的值,而非窃取服务器中的数据。
所以,我们要保护的对象是那些可以直接产生数据改变的服务,而对于读取数据的服务,则不需要进行CSRF 的保护。
比如银行系统中转账的请求会直接改变账户的金额,会遭到 CSRF攻击,需要保护。而查询余额是对金额的读取操作,不会改变数据,CSRF 攻击无法解析服务器返回的结果,无需保护。
如何防止 CSRF ?
CSRF 主流防御方式是在后端生成表单的时候生成一串随机 token ,内置到表单里成为一个字段,同时,将此串 token 置入 session 中。
每次表单提交到后端时都会检查这两个值是否一致,以此来判断此次表单提交是否是可信的。提交过一次之后,如果这个页面没有生成 CSRF token ,那么 token 将会被清空,如果有新的需求,那么 token 会被更新。
攻击者可以伪造 POST 表单提交,但是他没有后端生成的内置于表单的 token,session 中有没有 token 都无济于事。
text.html
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> {% csrf_token %} <input type="button" onclick="Do();" value="Do it"/> <script src="/static/plugin/jquery/jquery-1.8.0.js"></script> <script src="/static/plugin/jquery/jquery.cookie.js"></script> <script type="text/javascript"> var csrftoken = $.cookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection // GET|HEAD|OPTIONS|TRACE 这些http方法不提供CSRF防护 return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); function Do(){ $.ajax({ url:"/app01/test/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } </script> </body> </html>
最后
Django推荐放入请求头的token对应的key为 'X-CSRFtoken' # 如果key加了下划线会提示非法,非法的原因是django内部机制,它会将'X-CSRFtoken' 改为HTTP_X-CSRFTOKEN
所以ajex提交 格式为:headers:{'X-CSRFtoken': $.cookie('xxx')}