CSRF攻击原理
Cross Site Request Forgery 跨站请求伪造
一句话总结:都是cookie惹的祸,所以先看看cookie
cookie的作用流程
当输入一串网址登陆一个安全的站点如:www.XXX.com,并登陆到你的账号,服务器就会分配一个cookie给浏览器,里面包含了认证的信息,用户在这个站点打开其他的网页时将就不用再输入用户名和密码,浏览器会自动将这个cookie的值包含到请求中。服务器收到请求后,验证cookie的值是否和自己保存的值相同,如果是就证明用户身份合法,允许进行下一步的操作。这样做的好处就是简化的用户操作,不用没进行一步就要输入用户名密码 。
因为每个用户的生成的cookie都不同,cookie正确的话服务器可以认为对端是真实的用户。
然而,坏就坏在请求不一定是用户在了解的情况下发送的,这样对于这些请求浏览器也会带上cookie,服务器就仍然将它作为正常的消息处理,csrf正是利用了这一点,具体流程如下描述。
CSRF的攻击流程
user A 使用浏览器访问可信的网站website1进行业务,此时浏览器会保存website1相关的cookie
user A 使用浏览器访问一个不可信站点website2,如果website2中的网页具有指向website1的链接,攻击就有可能发生。有如下几种情况:
a、website2返回给用户的页面包含website1的链接,点击这个链接就会跳转到website1
b、website2返回给用户的页面包含<img src='XXX'>,其中XXX就是指向website1的链接,这样用户只要访问website2的页面就被攻击了,因为浏览器会解析<img src='XXX'>标签,自动获取XXX的’图片内容‘
c、website2返回给用户的页面包含自动加载的js,且js中有跳转到website1的动作,同上,用户只要访问website2就被攻击了
a、b、c三总跳转的方式不同但是利用的原理是一样的,那就是用户在本地还保存这website1的cookie,再次通过website2上的链接请求website1时,浏览器就会自动将website1对应的cookie加上,这样website1就会认为这个请求是用户合法请求而进行处理。
website2上的攻击者就可以通过编写特定的请求内容,进行攻击
Django的解决方法
Django预防CSRF攻击的方法是在用户提交的表单中加入一个csrftoken的隐含值,这个值和服务器中保存的csrftoken的值相同,这样做的原理如下:
1、在用户访问django的可信站点时,django反馈给用户的表单中有一个隐含字段csrftoken,这个值是在服务器端随机生成的,每一次提交表单都会生成不同的值
2、当用户提交django的表单时,服务器校验这个表单的csrftoken是否和自己保存的一致,来判断用户的合法性
3、当用户被csrf攻击从其他站点发送精心编制的攻击请求时,由于其他站点不可能知道隐藏的csrftoken字段的信息这样在服务器端就会校验失败,攻击被成功防御
具体配置如下:
template中添加{%csrf_token%}标签
<form enctype="multipart/form-data" action="/wxroot/JS/upload_file/" method="post">
{% csrf_token %}
<input type="file" name="myfile" />
<br/>
<input type="submit" value="upload"/>
</form>
如果是js提交的post请求,需要添加header X-CSRFToken
完整代码如下:
// using jQuery
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function uploadFile() {
var fd = new FormData();
fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
var xhr = new XMLHttpRequest();
var csrftoken = getCookie('csrftoken');
xhr.upload.addEventListener("progress", uploadProgress, false);
xhr.addEventListener("load", uploadComplete, false);
xhr.addEventListener("error", uploadFailed, false);
xhr.addEventListener("abort", uploadCanceled, false);
xhr.open("POST", "/wxroot/JS/upload_file");
xhr.setRequestHeader("X-CSRFToken", csrftoken);
xhr.send(fd);
}
总结
但是django这种做法也是在用户的cookie是安全的基础之上,如果用户的cookie被盗取,那么攻击者就不用这么麻烦了,直接就可以获取用户的所有权限,而cookie又是很容易通过js获取的,所以一切的根源在于cookie,只有改变cookie这种机制才能从根源解决这个问题
FAQ
1、使用js提交post请求包含X-CSRFToken时异常InvalidStateError
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable
InvalidStateError, DOMException code 11
代码调用的方法在当前状态无法调用。通常由 XMLHttpRequest
引起,在方法准备完毕之前调用它会引起错误。
var xhr = new XMLHttpRequest();
xhr.setRequestHeader('Some-Header', 'val');
这时就会出错,因为 setRequestHeader
方法只能在 xhr.open
方法之后调用。
将setRequestHeader
放到open
方法后面问题解决