老社长面临毕业,接下来社团负责人选择了我,社团叫MIIE移动互联,以参加省赛为初衷,但我并不想让他光为了参加省赛存活,选择了 讲课的方式进行平常的社团活动,第一堂课,准备讲CSRF跨站攻击的原理,以及实现方法,以及Dango预防CSRF实现方法。
CSRF跨站信息伪造攻击是什么?
比较专业点讲,叫中间人攻击。以我的通俗点的理解,就是 只针对与POST 请求发起的,依靠浏览器存储的Seesion字典的”键“信息,来伪造用户向服务器发起请求,以达到修改用户数据,获取用户信息等一系列危害的一种常见的攻击手段。
CSRF跨站信息伪造攻击演示(Django演示):
用户正常访问网站需要经历这几步:
填写用户名密码,点击登录按钮。
而CSRF跨站请求攻击则需要经过以下步骤:
用户输入用户名和密码,点击submit提交,正常的步骤,URL会首先重定向到”/POSTD(某个验证用户身份的网址)“
这个url地址,在这个地址中判断用户名密码是否正确,如果正确,就在数据库里添加一条 {‘islogn’: True}
的信息,并返回这正确的页面,返回的信息里记录了这条session的键信息”islogn“
。然鹅或许某一次当你不小心点击了某个地方,打开了某个第三方网站页面,并点击了这个页面中某不该点击的地方,此时第三方网站会伪造你的用户信息向服务器发起请求,强制完成某些操作。这个第三方网站是怎么做到的呢?其实很简单,它只需要完全仿造你登陆页面的POST表单里面的”method=POST“和”action=’/POSTD‘“
信息,然后稍加界面的改动,引导你去点击某提交按钮,就可以达到使用你本地保存的Session信息伪造你的身份登陆的目的。
Dango源码中自带预防CSRF跨站信息伪造攻击:
对于Django开发的网站,我们并不需要担心 CSRF跨站请求攻击,因为在Django源码中已经有实现预防的方法了,不需要你去过多的担心,如下图所示,当我们用Dango开发的网站去访问第三方非法网站构建CSRF跨站请求伪造的时候,它会爆出Fobidden403错误
的提示页面(如图所示)。期间涉及到一个问题,我们预防了CSRF,可是当我们正常访问跳转页面的时候也会被Fobidden403
,这就牵扯到Django中实现预防CSRF的原理问题了。这一段我们先说一下解决办法,下一段重点说原理。
最理想的解决办法就是,在POST 请求的任意位置加上{% csrf_token %}
,(如下图所示),我们自己可以正常跳转,并且也完美的阻止了第三方网站非法伪造用户信息登陆的问题。
Django中实现防止CSRF跨站攻击的原理:
Django中实现在一定程度上防止CSRF,但是也不否认有造成CSRF的可能,接下来讲完原理就明白为什么只不过是一定程度预防,而不是绝对阻止:
我们上面说了,Django中有自带的预防针机制,如果我们不在POST表单中添加{% csrf_token %}
信息,正常跳转页面也会被阻止,这是为什么呢?
当我们加上{% csrf_token %}
信息在POST表单中以后,我们再模拟一下用户登录:首先,输入账户名密码,点击Submit提交,然后正确跳转到登陆成功的页面,此时,我们回到刚才的登陆页面,查看一下网页源代码,此时会发现,刚刚{% csrf_token %}
的信息,被替换成
了一个隐藏的input标签
,标签内容为:<input type='hidden' name='csrfmiddlewaretoken' value='cLE1uB8qf5VzGqLu3unuRyN285GSPYbM' />
,我们可以看到,登陆页面此时隐藏了一个向服务器提交的input标签。我们再切换到已经成功登录的页面,查看一下它的传递给服务器的参数,我们比较一下得知,其中有一个参数(csrfmiddlewaretoken:cLE1uB8qf5VzGqLu3unuRyN285GSPYbM)
和input表单里隐藏的 name 和 value时相同的,我们就知道了,它交给服务器的,除了用户名密码外,还有把{% csrf_token %}
替换成隐藏的inout标签中的数据,而服务器就是通过比较浏览器提交的这个隐藏的数据,以及自己数据库里的Seesion信息是否匹配来判断是否为CSRF攻击的。
当然,我们刚刚说了,这种方法在一定程度上预防了CSRF攻击,但也不能完全阻止,设想只要攻击者拿到了你隐藏的这个和服务器之间的”暗号“,是可以发起CSRF跨站请求伪造攻击的。只不过,难度很大,没有人会来你的电脑上右击先查看源码,赋值隐藏的input信息粘到第三方网站,来构成CSRF攻击的
如何屏蔽Django的CSRF防护机制?
这里提供三种措施,是自己初学Django的时候遇到CSRF不知道如何解决才使用的办法:
【1】注释settings中的:‘django.middleware.csrf.CsrfViewMiddleware’
【2】引用官方 js防止错误的文件(文章末尾有源码)
【3】在 views.py 中在不需要CSRF验证的函数前加装饰:@csrf_exempt
//防止403 forbidden
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 csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
var csrftoken = getCookie('csrftoken');
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});