zoukankan      html  css  js  c++  java
  • Django之中间件,csrf跨站伪造请求,auth认证模块

    Django请求生命周期

    django的中间件

    django的中间件相当于保安,请求的时候要经过django的中间件才能连接django的后端

    能用来干什么:能够做网站的全局身份认证,访问频率,权限认证,只要是全局的校验都可以用中间件来完成。

    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',
                                ]
    class SecurityMiddleware(MiddlewareMixin):
                        def __init__(self, get_response=None):
                            self.sts_seconds = settings.SECURE_HSTS_SECONDS
                            self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS
                            self.sts_preload = settings.SECURE_HSTS_PRELOAD
                            self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF
                            self.xss_filter = settings.SECURE_BROWSER_XSS_FILTER
                            self.redirect = settings.SECURE_SSL_REDIRECT
                            self.redirect_host = settings.SECURE_SSL_HOST
                            self.redirect_exempt = [re.compile(r) for r in settings.SECURE_REDIRECT_EXEMPT]
                            self.get_response = get_response
    
                        def process_request(self, request):
                            path = request.path.lstrip("/")
                            if (self.redirect and not request.is_secure() and
                                    not any(pattern.search(path)
                                            for pattern in self.redirect_exempt)):
                                host = self.redirect_host or request.get_host()
                                return HttpResponsePermanentRedirect(
                                    "https://%s%s" % (host, request.get_full_path())
                                )
    
                        def process_response(self, request, response):
                            if (self.sts_seconds and request.is_secure() and
                                    'strict-transport-security' not in response):
                                sts_header = "max-age=%s" % self.sts_seconds
                                if self.sts_include_subdomains:
                                    sts_header = sts_header + "; includeSubDomains"
                                if self.sts_preload:
                                    sts_header = sts_header + "; preload"
                                response["strict-transport-security"] = sts_header
    
                            if self.content_type_nosniff and 'x-content-type-options' not in response:
                                response["x-content-type-options"] = "nosniff"
    
                            if self.xss_filter and 'x-xss-protection' not in response:
                                response["x-xss-protection"] = "1; mode=block"
    
                            return response
                    
                    class CsrfViewMiddleware(MiddlewareMixin):
                            if settings.CSRF_USE_SESSIONS:
                                request.session[CSRF_SESSION_KEY] = request.META['CSRF_COOKIE']
                            else:
                                response.set_cookie(
                                    settings.CSRF_COOKIE_NAME,
                                    request.META['CSRF_COOKIE'],
                                    max_age=settings.CSRF_COOKIE_AGE,
                                    domain=settings.CSRF_COOKIE_DOMAIN,
                                    path=settings.CSRF_COOKIE_PATH,
                                    secure=settings.CSRF_COOKIE_SECURE,
                                    httponly=settings.CSRF_COOKIE_HTTPONLY,
                                )
                                # Set the Vary header since content varies with the CSRF cookie.
                                patch_vary_headers(response, ('Cookie',))
                        def process_request(self, request):
                            csrf_token = self._get_token(request)
                            if csrf_token is not None:
                                # Use same token next time.
                                request.META['CSRF_COOKIE'] = csrf_token
    
                        def process_view(self, request, callback, callback_args, callback_kwargs):
                            if getattr(request, 'csrf_processing_done', False):
                                return None
    
                            # Wait until request.META["CSRF_COOKIE"] has been manipulated before
                            # bailing out, so that get_token still works
                            if getattr(callback, 'csrf_exempt', False):
                                return None
    
                            # Assume that anything not defined as 'safe' by RFC7231 needs protection
                            if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
                                if getattr(request, '_dont_enforce_csrf_checks', False):
                                    # Mechanism to turn off CSRF checks for test suite.
                                    # It comes after the creation of CSRF cookies, so that
                                    # everything else continues to work exactly the same
                                    # (e.g. cookies are sent, etc.), but before any
                                    # branches that call reject().
                                    return self._accept(request)
    
                                if request.is_secure():
                                    # Suppose user visits http://example.com/
                                    # An active network attacker (man-in-the-middle, MITM) sends a
                                    # POST form that targets https://example.com/detonate-bomb/ and
                                    # submits it via JavaScript.
                                    #
                                    # The attacker will need to provide a CSRF cookie and token, but
                                    # that's no problem for a MITM and the session-independent
                                    # secret we're using. So the MITM can circumvent the CSRF
                                    # protection. This is true for any HTTP connection, but anyone
                                    # using HTTPS expects better! For this reason, for
                                    # https://example.com/ we need additional protection that treats
                                    # http://example.com/ as completely untrusted. Under HTTPS,
                                    # Barth et al. found that the Referer header is missing for
                                    # same-domain requests in only about 0.2% of cases or less, so
                                    # we can use strict Referer checking.
                                    referer = force_text(
                                        request.META.get('HTTP_REFERER'),
                                        strings_only=True,
                                        errors='replace'
                                    )
                                    if referer is None:
                                        return self._reject(request, REASON_NO_REFERER)
    
                                    referer = urlparse(referer)
    
                                    # Make sure we have a valid URL for Referer.
                                    if '' in (referer.scheme, referer.netloc):
                                        return self._reject(request, REASON_MALFORMED_REFERER)
    
                                    # Ensure that our Referer is also secure.
                                    if referer.scheme != 'https':
                                        return self._reject(request, REASON_INSECURE_REFERER)
    
                                    # If there isn't a CSRF_COOKIE_DOMAIN, require an exact match
                                    # match on host:port. If not, obey the cookie rules (or those
                                    # for the session cookie, if CSRF_USE_SESSIONS).
                                    good_referer = (
                                        settings.SESSION_COOKIE_DOMAIN
                                        if settings.CSRF_USE_SESSIONS
                                        else settings.CSRF_COOKIE_DOMAIN
                                    )
                                    if good_referer is not None:
                                        server_port = request.get_port()
                                        if server_port not in ('443', '80'):
                                            good_referer = '%s:%s' % (good_referer, server_port)
                                    else:
                                        # request.get_host() includes the port.
                                        good_referer = request.get_host()
    
                                    # Here we generate a list of all acceptable HTTP referers,
                                    # including the current host since that has been validated
                                    # upstream.
                                    good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
                                    good_hosts.append(good_referer)
    
                                    if not any(is_same_domain(referer.netloc, host) for host in good_hosts):
                                        reason = REASON_BAD_REFERER % referer.geturl()
                                        return self._reject(request, reason)
    
                                csrf_token = request.META.get('CSRF_COOKIE')
                                if csrf_token is None:
                                    # No CSRF cookie. For POST requests, we insist on a CSRF cookie,
                                    # and in this way we can avoid all CSRF attacks, including login
                                    # CSRF.
                                    return self._reject(request, REASON_NO_CSRF_COOKIE)
    
                                # Check non-cookie token for match.
                                request_csrf_token = ""
                                if request.method == "POST":
                                    try:
                                        request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
                                    except IOError:
                                        # Handle a broken connection before we've completed reading
                                        # the POST data. process_view shouldn't raise any
                                        # exceptions, so we'll ignore and serve the user a 403
                                        # (assuming they're still listening, which they probably
                                        # aren't because of the error).
                                        pass
    
                                if request_csrf_token == "":
                                    # Fall back to X-CSRFToken, to make things easier for AJAX,
                                    # and possible for PUT/DELETE.
                                    request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
    
                                request_csrf_token = _sanitize_token(request_csrf_token)
                                if not _compare_salted_tokens(request_csrf_token, csrf_token):
                                    return self._reject(request, REASON_BAD_TOKEN)
    
                            return self._accept(request)
    
                        def process_response(self, request, response):
                            if not getattr(request, 'csrf_cookie_needs_reset', False):
                                if getattr(response, 'csrf_cookie_set', False):
                                    return response
    
                            if not request.META.get("CSRF_COOKIE_USED", False):
                                return response
    
                            # Set the CSRF cookie even if it's already set, so we renew
                            # the expiry timer.
                            self._set_token(request, response)
                            response.csrf_cookie_set = True
                            return response
                    
                                    
                    class AuthenticationMiddleware(MiddlewareMixin):
                        def process_request(self, request):
                            assert hasattr(request, 'session'), (
                                "The Django authentication middleware requires session middleware "
                                "to be installed. Edit your MIDDLEWARE%s setting to insert "
                                "'django.contrib.sessions.middleware.SessionMiddleware' before "
                                "'django.contrib.auth.middleware.AuthenticationMiddleware'."
                            ) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
                            request.user = SimpleLazyObject(lambda: get_user(request))
                    

    django中间件可以自定义有五种方法

    掌握:

    1.process_request()方法

    规律:
    请求来的时候,会从上往下依次执行每个中间件里面的process_request方法,如果没有就跳过。
    但需要注意的是,如果在某个中间件的process_request方法中返回了一个HttpResponse对象的话,那么就不会在走下面的中间件了,会在同级别从下往上依次执行每个中间件的process_response方法

    2.process_response()方法

    响应走的时候,会从下至上依次执行每个中间件的process_response方法。
    不过要注意的是,最后要返回一个response,这个形参就是返回给浏览器的数据,只要是参数有response的,最后都要返回一下,因为返回的response就是代表要返回给浏览器的数据,如果没有就是代表你想截获它

    了解

    3.process_view

    这个方法是在路由匹配成功,进入视图层前执行的一个方法,但要注意的是如果我某一个中间件的process_view()方法里面返回了一个HttpResponse对象,则会掉头,从最底下,从下往上依次执行每个中间件的process_respnse方法

    4.process_exception

    这个方法要报错的时候才会执行,顺序从下往上

    5.process_template_response()

    是返回的对象含有render这个方法的时候执行,顺序是从下往上
    def index(request):
           print('我是index视图函数')
            def render():
                 return HttpResponse('什么鬼玩意')
            obj = HttpResponse('index')
            obj.render = render
            return obj

    注意:如果要想让你写的中间件有效,那么写的类一定要继承自MiddlemareMixin

        在seetings中注册自定义的中间件的时候,一定要注意路径不要写错

    Csrf跨站请求伪造(钓鱼网站)

    钓鱼网站

    就是制作一个正儿八经的网站,欺骗用户转账

    你比如中国银行转账,交易请求确确实实发送给了中国银行,也的确完成了交易,但是就是交易方不对。

    内部原理:
    就是在用户输入转账用户的那个input框做手脚

    给这个input框不设置name属性,而是将这个设置下隐藏在下面的input框内,value值就是钓鱼网站受益人账号。

    防止钓鱼网站的思路:

    给每个返回给用户输入的form表单页面偷偷塞入一个特殊的随机字符串。

    请求来的时候,会先比较是否与我保存的一致,不一致就不通过报个(403)

    该随机字符串有以下特点:
      1.同一个浏览器每一次访问都不一样

      2.不同浏览器绝对不会重复

    form表单来的时候就是固定一句话

    {% csrf_token %}

    ajax来的时候有3种避免csrf校验的

    1.现在页面上写{% csrf_token %},利用标签查找  获取到该input键值信息
                    {'username':'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()}
                    $('[name=csrfmiddlewaretoken]').val()
                    
                2.直接书写'{{ csrf_token }}'
                    {'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}
                    {{ csrf_token }}
                
                3.你可以将该获取随机键值对的方法 写到一个js文件中,之后只需要导入该文件即可
                    新建一个js文件 存放以下代码 之后导入即可 
                    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;
                    }
                    var csrftoken = getCookie('csrftoken');
    
    
                    function csrfSafeMethod(method) {
                      // these HTTP methods do not require CSRF protection
                      return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
                    }
    
                    $.ajaxSetup({
                      beforeSend: function (xhr, settings) {
                        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                          xhr.setRequestHeader("X-CSRFToken", csrftoken);
                        }
                      }
                    });

    接下来的2中需求

    1.全部都要校验,但有几个不想让其校验

    2.全部都不检验,但有几个想要其校验

            from django.utils.decorators import method_decorator    
                from django.views.decorators.csrf import csrf_exempt,csrf_protect
                # 这两个装饰器在给CBV装饰的时候 有一定的区别
                如果是csrf_protect 那么有三种方式
                    # 第一种方式
                    # @method_decorator(csrf_protect,name='post')  # 有效的
                    class MyView(View):
                        # 第三种方式
                        # @method_decorator(csrf_protect)
                        def dispatch(self, request, *args, **kwargs):
                            res = super().dispatch(request, *args, **kwargs)
                            return res
    
                        def get(self,request):
                            return HttpResponse('get')
                        # 第二种方式
                        # @method_decorator(csrf_protect)  # 有效的
                        def post(self,request):
                            return HttpResponse('post')
                        
                如果是csrf_exempt 只有两种(只能给dispatch装)   特例
                @method_decorator(csrf_exempt,name='dispatch')  # 第二种可以不校验的方式
                class MyView(View):
                    # @method_decorator(csrf_exempt)  # 第一种可以不校验的方式
                    def dispatch(self, request, *args, **kwargs):
                        res = super().dispatch(request, *args, **kwargs)
                        return res
    
                    def get(self,request):
                        return HttpResponse('get')
    
                    def post(self,request):
                        return HttpResponse('post')
            
            总结 装饰器中只有csrf_exempt是特例,其他的装饰器在给CBV装饰的时候 都可以有三种方式

    Auth用户登录认证模块

    auth模块
                如果你想用auth模块   那么你就用全套
                
                
                
                跟用户相关的功能模块
                    用户的注册 登陆 验证 修改密码 ...
                
                执行数据库迁移命令之后  会生成很多表  其中的auth_user是一张用户相关的表格
                添加数据
                    createsuperuser  创建超级用户 这个超级用户就可以拥有登陆django admin后台管理的权限
            
    
            auth模块的功能
                查询用户
                    from django.contrib import auth
                    user_obj = auth.authenticate(username=username,password=password)  # 必须要用 因为数据库中的密码字段是密文的 而你获取的用户输入的是明文
                记录用户状态
                    auth.login(request,user_obj)  # 将用户状态记录到session中
                判断用户是否登录
                    print(request.user.is_authenticated)  # 判断用户是否登录  如果是你们用户会返回False
                用户登录之后 获取用户对象
                    print(request.user)  # 如果没有执行auth.login那么拿到的是匿名用户
                校验用户是否登录
                    from django.contrib.auth.decorators import  login_required
                    @login_required(login_url='/xxx/')  # 局部配置
                    def index(request):
                        pass
                    
                    # 全局配置  settings文件中
                    LOGIN_URL = '/xxx/'
                验证密码是否正确
                    request.user.check_password(old_password)
                修改密码    
                    request.user.set_password(new_password)
                    request.user.save()  # 修改密码的时候 一定要save保存 否则无法生效
                退出登陆
                    auth.logout(request)  # request.session.flush()
                注册用户
                        # User.objects.create(username =username,password=password)  # 创建用户名的时候 千万不要再使用create 了
                        # User.objects.create_user(username =username,password=password)  # 创建普通用户
                        User.objects.create_superuser(username =username,password=password,email='123@qq.com')  # 创建超级用户  邮箱必填
            
            
            自定义auth_user表
                from django.contrib.auth.models import AbstractUser
                # Create your models here.
                # 第一种 使用一对一关系  不考虑
    
    
    
                # 第二种方式   使用类的继承
                class Userinfo(AbstractUser):
                    # 千万不要跟原来表中的字段重复 只能创新
                    phone = models.BigIntegerField()
                    avatar = models.CharField(max_length=32)
                
                # 一定要在配置文件中 告诉django
                # 告诉django  orm不再使用auth默认的表  而是使用你自定义的表
                AUTH_USER_MODEL = 'app01.Userinfo'  # '应用名.类名'
            
            
            1.执行数据库迁移命令
                所有的auth模块功能 全部都基于你创建的表 
                而不再使用auth_user
  • 相关阅读:
    非root用户在linux下安装多个版本的CUDA和cuDNN(cuda 8、cuda 10.1 等)
    python相关总结
    可视化滤波器
    Ubuntu 和windows程序区别
    远程服务器运行代码相关
    Ubuntu
    jmeter学习(1)基础支持+安装部署
    python中eval方法的使用
    mysql学习(4)python操作数据库
    mysql学习(3)10045错误,连接不上数据库
  • 原文地址:https://www.cnblogs.com/xinfan1/p/11587095.html
Copyright © 2011-2022 走看看