Django之中间件,csrf跨站伪造请求,auth认证模块

Django请求生命周期

 

 

django的中间件

django的中间件至关于保安,请求的时候要通过django的中间件才能链接django的后端ajax

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

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中间件能够自定义有五种方法

掌握: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中注册自定义的中间件的时候,必定要注意路径不要写错cookie

 

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

钓鱼网站session

就是制做一个正儿八经的网站,欺骗用户转帐app

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

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

给这个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
相关文章
相关标签/搜索