django的中間件至關於保安,請求的時候要通過django的中間件才能鏈接django的後端ajax
能用來幹什麼:可以作網站的全局身份認證,訪問頻率,權限認證,只要是全局的校驗均可以用中間件來完成。數據庫
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
規律: 請求來的時候,會從上往下依次執行每一箇中間件裏面的process_request方法,若是沒有就跳過。
但須要注意的是,若是在某個中間件的process_request方法中返回了一個HttpResponse對象的話,那麼就不會在走下面的中間件了,會在同級別從下往上依次執行每一箇中間件的process_response方法
響應走的時候,會從下至上依次執行每一箇中間件的process_response方法。 不過要注意的是,最後要返回一個response,這個形參就是返回給瀏覽器的數據,只要是參數有response的,最後都要返回一下,由於返回的response就是表明要返回給瀏覽器的數據,若是沒有就是表明你想截獲它
瞭解後端
這個方法是在路由匹配成功,進入視圖層前執行的一個方法,但要注意的是若是我某一箇中間件的process_view()方法裏面返回了一個HttpResponse對象,則會掉頭,從最底下,從下往上依次執行每一箇中間件的process_respnse方法
這個方法要報錯的時候纔會執行,順序從下往上
是返回的對象含有render這個方法的時候執行,順序是從下往上 def index(request): print('我是index視圖函數') def render(): return HttpResponse('什麼鬼玩意') obj = HttpResponse('index') obj.render = render return obj
注意:若是要想讓你寫的中間件有效,那麼寫的類必定要繼承自MiddlemareMixin瀏覽器
在seetings中註冊自定義的中間件的時候,必定要注意路徑不要寫錯cookie
釣魚網站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