什么是CSRF

维基百科:

跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。

攻击细节:

跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并执行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去执行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。

防御措施:

检查Referer字段

HTTP头中有一个Referer字段,这个字段用以标明请求来源于哪个地址。在处理敏感数据请求时,通常来说,Referer字段应和请求的地址位于同一域名下。以上文银行操作为例,Referer字段地址通常应该是转账按钮所在的网页地址,应该也位于www.examplebank.com之下。而如果是CSRF攻击传来的请求,Referer字段会是包含恶意网址的地址,不会位于www.examplebank.com之下,这时候服务器就能识别出恶意的访问。

这种办法简单易行,工作量低,仅需要在关键访问处增加一步校验。但这种办法也有其局限性,因其完全依赖浏览器发送正确的Referer字段。虽然http协议对此字段的内容有明确的规定,但并无法保证来访的浏览器的具体实现,亦无法保证浏览器没有安全漏洞影响到此字段。并且也存在攻击者攻击某些浏览器,篡改其Referer字段的可能。

添加校验token

由于CSRF的本质在于攻击者欺骗用户去访问自己设置的地址,所以如果要求在访问敏感数据请求时,要求用户浏览器提供不保存在cookie中,并且攻击者无法伪造的数据作为校验,那么攻击者就无法再执行CSRF攻击。这种数据通常是表单中的一个数据项。服务器将其生成并附加在表单中,其内容是一个伪乱数。当客户端通过表单提交请求时,这个伪乱数也一并提交上去以供校验。正常的访问时,客户端浏览器能够正确得到并传回这个伪乱数,而通过CSRF传来的欺骗性攻击中,攻击者无从事先得知这个伪乱数的值,服务器端就会因为校验token的值为空或者错误,拒绝这个可疑请求。

Django中防范CSRF

Django的中间件

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

其中'django.middleware.csrf.CsrfViewMiddleware',就是负责验证 csrf_token 的。

写一个简单的用户登陆

urls.py

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^login/$', views.login),
    url(r'^index/$', views.index),
]

views.py

from django.shortcuts import render, HttpResponse, redirect

def login(request):
    if request.method == 'POST':
        username = request.POST.get('user')
        password = request.POST.get('pwd')
        if username == 'lcg' and password == '123':
            return redirect('/index/')
    return render(request, 'login.html')

def index(request):
    return HttpResponse('登录成功!')

login.html

<form action="/login/" method="post">
    <input type="text" placeholder="username" name="user">
    <input type="password" placeholder="password" name="pwd">
    <input type="submit" value="登录">
</form>

启动项目。进入login界面

当我输入用户名密码,点击登陆的时候,会报错:

下面我在login.html中加上csrf_token

<form action="/login/" method="post">
    {% csrf_token %}
    <input type="text" placeholder="username" name="user">
    <input type="password" placeholder="password" name="pwd">
    <input type="submit" value="登录">
</form>

此时再登陆就可以成功登陆!

审查元素看一下此时的Elements与之前有何不同:

此时,其实是多了一个input框,type="hidden"属性是隐藏的功能。

我们知道,防范CSRF攻击的一个办法可以是请求的时候带一个 token,到服务器验证 token 的有效性。django 对于 csrf 的防御主要在 middleware 实现,项目的settings.py中包含 django.middleware.csrf.CsrfViewMiddleware 这个中间件,默认是开始 csrf 防御的。每次在模板里写 form 时都知道要加一个 {% csrf_token %} ,如果是Ajax请求,也要携带 这个值,否则验证不通过会报Forbidden的错。

Ajax登录:

urls.py

from django.conf.urls import url

from . import views
urlpatterns = [
    url(r'^login/$', views.login),
    url(r'^index/$', views.index),
]

views.py

from django.shortcuts import render, HttpResponse, redirect
import json

def login(request):
    if request.method == 'POST':
        username = request.POST.get('user')
        password = request.POST.get('pwd')
        loginResponse = {"username": None, "error_msg": None}
        if username == 'lcg' and password == '123':
            loginResponse["username"] = username
        else:
            loginResponse["error_msg"] = "username or password is wrong!"
        return HttpResponse(json.dumps(loginResponse))
    return render(request, 'login.html')

def index(request):
    return HttpResponse('登录成功!')

login.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>ajax登录</title>
</head>
<body>

{% csrf_token %}
<input type="text" placeholder="username" id="user">
<input type="password" placeholder="password" id="pwd">
<button id="btn">登录</button>
<span id="error"></span>

<script src="/static/js/jquery-3.2.1.min.js"></script>
<script>
    $("#btn").on('click', function () {
        $.ajax({
            url: "/login/",
            type: "POST",
            data: {
                user: $("#user").val(),
                pwd: $("#pwd").val(),
                csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
            },
            success: function (arg) {
                var arg = JSON.parse(arg);
                if (arg.username) {
                    location.href = "/index/"
                }
                else {
                    $("#error").text(arg.error_msg).css("color", "red")
                }
            }
        })
    });
</script>
</body>
</html>

效果:

输入错误:

输入正确:

Django Ajax登录 防止CSRF的更多相关文章

  1. python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页)

    一.ajax登录示例 新建项目login_ajax 修改urls.py,增加路径 from app01 import views urlpatterns = [ path('admin/', admi ...

  2. 关于Django Ajax CSRF 认证

    CSRF(Cross-site request forgery跨站请求伪造,也被称为“one click attack”或者session riding,通常缩写为CSRF或者XSRF,是一种对网站的 ...

  3. Django 博客项目01 数据库设计与验证码校验+Ajax登录

    数据库设计 from django.db import models from django.contrib.auth.models import AbstractUser class UserInf ...

  4. python学习-- Django Ajax CSRF 认证

    使用 jQuery 的 ajax 或者 post 之前 加入这个 js 代码:http://www.ziqiangxuetang.com/media/django/csrf.js /*======== ...

  5. Django(十二)视图--利用jquery从后台发送ajax请求并处理、ajax登录案例

    一.Ajax基本概念 [参考]:https://www.runoob.com/jquery/jquery-ajax-intro.html 异步的javascript.在不全部加载某一个页面部的情况下, ...

  6. Django学习系列之CSRF

    Django CSRF 什么是CSRF CSRF, Cross Site Request Forgery, 跨站点伪造请求.举例来讲,某个恶意的网站上有一个指向你的网站的链接,如果 某个用户已经登录到 ...

  7. 玩转Django的POST请求 CSRF

    玩转Django的POST请求 CSRF 不少麻油们玩django都会碰到这个问题,POST请求莫名其妙的返回 403 foribidden,希望这篇博文能解答所有问题 三种方法 To enable ...

  8. Django ajax MYSQL Highcharts<1>

    Another small project with django/Ajax/Mysql/Highcharts. 看下效果图  - delivery dashboard .嘿嘿 是不是还蛮好看的. 废 ...

  9. django ajax报错解决:You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set.

    Django版本号:1.11.15 django中ajax请求报错:You called this URL via POST, but the URL doesn't end in a slash a ...

随机推荐

  1. Access-Control-Allow-Origin实现跨域访问 跨域

    总结:跨域的get,post请求 后台可以设置 Access-Control-*相关的参数,让浏览器支持. // 指定允许其他域名访问 header('Access-Control-Allow-Ori ...

  2. Python gui编程pyQt5安装步骤t

    Python gui编程pyQt5安装步骤         pip install PyQt5 Pip3 install PyQt5               https://riverbankco ...

  3. ASP.NET的MVC中Model对象字段的数…

    ASP.NET的MVC中Model对象字段的常用数据说明属性: Required——该字段不允许为空. MaxLength——设置数组或字符串最大长度. StringLength——设置字符串最小和最 ...

  4. noip2005循环

    题解: 迭代,一次次k累加计算 代码: #include<bits/stdc++.h> using namespace std; ; ][N],ans[N]; char s[N]; boo ...

  5. .net WebService方法之重载、支持Session、支持request请求和response格式的浅析

    .net的webservice不支持web方法的重载,但是可以通过设置WebMethod属性的MessageName字段来达到重载web方法的目的. 通过设置WebMethod属性的EnableSes ...

  6. MyEclipse WebSphere开发教程:安装和更新WebSphere 6.1, JAX-WS, EJB 3.0(五)

    MyEclipse超值折扣 限量 100 套! 立即开抢>> [MyEclipse最新版下载] MyEclipse支持Java EE技术(如JAX-WS和EJB 3.0),它们以功能包的形 ...

  7. Okhttp对http2的支持简单分析

    在< Okhttp之RealConnection建立链接简单分析>一文中简单的分析了RealConnection的connect方法的作用:打开一个TCP链接或者打开一个隧道链接,在打开t ...

  8. UI基础:UITableView表视图

    表视图 UITableView,iOS中最重要的视图,随处可见. 表视图通常用来管理一组具有相同数据结构的数据. UITableView继承于UIScrollView,所以可以滚动 表视图的每条数据都 ...

  9. Android Studio中设置提示函数用法

    Eclipse有一个很好的功能,就是当你代码调用某个android API时,鼠标移到对应的函数或者方法上,就会自动有一个悬浮窗提示该函数的说明(所包含的参数含义,该方法功能).迁移到Android ...

  10. Struck: Structured Output Tracking with Kernels

    reference: Struck: Structured Output Tracking with Kernels hot topic: tracking-by-detection methods, ...