django自身安全機制-XSS和csrf


xss攻擊:----->web注入

定義:

  xss跨站腳本攻擊(Cross site script,簡稱xss)是一種“HTML注入”,由於攻擊的腳本多數時候是跨域的,所以稱之為“跨域腳本”。
  我們常常聽到“注入”(Injection),如SQL注入,那么到底“注入”是什么?注入本質上就是把輸入的數據變成可執行的程序語句。SQL注入是如此,XSS也如此,只不過XSS一般注入的是惡意的腳本代碼,這些腳本代碼可以用來獲取合法用戶的數據,如Cookie信息。
  PS: 把用戶輸入的數據以安全的形式顯示,那只能是在頁面上顯示字符串。
    django框架中給數據標記安全方式顯示(但這種操作是不安全的!):
      - 模版頁面上對拿到的數據后寫上safe. ----> {{XXXX|safe}}
      - 在后台導入模塊:from django.utils.safestring import mark_safe
        把要傳給頁面的字符串做安全處理 ----> s = mark_safe(s)

實施XSS攻擊需要具備兩個條件:

  一、需要向web頁面注入惡意代碼;

  二、這些惡意代碼能夠被瀏覽器成功的執行。

解決辦法:

  1、一種方法是在表單提交或者url參數傳遞前,對需要的參數進行過濾。
  2、在后台對從數據庫獲取的字符串數據進行過濾,判斷關鍵字。
  3、設置安全機制。
  django框架:內部機制默認阻止了。它會判定傳入的字符串是不安全的,就不會渲染而以字符串的形式顯示。如果手賤寫了safe,那就危險了,若想使用safe,那就必須在后台對要渲染的字符串做過濾了。所以在開發的時候,一定要慎用安全機制。尤其是對用戶可以提交的並能渲染的內容!!!

- 示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <form method="POST" action="/comment/">
        <h4>評論</h4>
        <input type="text" name="content"/>
        <input type="submit" value="提交" />{{ error }}
    </form>
</body>
</html>
comment.html :評論提交頁面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>評論內容</h1>
    {% for item in msg %}
        <div>{{ item|safe }}</div>
    {% endfor %}
</body>
</html>
index.html 評論顯示頁面:
from django.shortcuts import render
msg = []
def comment(request):
        if request.method == "GET":
        return render(request,'comment.html')
    else:
        v = request.POST.get('content')
        if "script" in v:
            return render(request,'comment.html',{'error': '小比崽子還黑我'})
        else:
            msg.append(v)
            return render(request,'comment.html')

def index(request):
    return render(request,'index.html',{'msg':msg})

def test(request):
    from django.utils.safestring import mark_safe
    temp = "<a href='http://www.baidu.com'>百度</a>"
    newtemp = mark_safe(temp)
    return render(request,'test.html',{'temp':newtemp}
views.py 后台處理

csrf: Cross Site Request Forgery, 跨站請求偽造

什么是 CSRF

  CSRF, Cross Site Request Forgery, 跨站點請求偽造。舉例來講,某個惡意的網站上有一個指向你的網站的鏈接,如果某個用戶已經登錄到你的網站上了,那么當這個用戶點擊這個惡意網站上的那個鏈接時,就會向你的網站發來一個請求,你的網站會以為這個請求是用戶自己發來的,其實呢,這個請求是那個惡意網站偽造的。

經典案例:銀行轉賬:

  CSRF 攻擊可以在受害者毫不知情的情況下以受害者名義偽造請求發送給受攻擊站點,從而在並未授權的情況下執行在權限保護之下的操作。
  比如說,受害者 Bob 在銀行有一筆存款,通過對銀行的網站發送請求 http://bank.example/withdraw?account=bob&amount=1000000&for=bob2 可以使 Bob 把 1000000 的存款轉到 bob2 的賬號下。通常情況下,該請求發送到網站后,服務器會先驗證該請求是否來自一個合法的 session,並且該 session 的用戶 Bob 已經成功登陸。黑客 Mallory 自己在該銀行也有賬戶,他知道上文中的 URL 可以把錢進行轉帳操作。Mallory 可以自己發送一個請求給銀行:http://bank.example/withdrawaccount=bob&amount=1000000&for=Mallory。但是這個請求來自 Mallory 而非 Bob,他不能通過安全認證,因此該請求不會起作用。這時,Mallory 想到使用 CSRF 的攻擊方式,他先自己做一個網站,在網站中放入如下代碼: src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory ”,並且通過廣告等誘使 Bob 來訪問他的網站。當 Bob 訪問該網站時,上述 url 就會從 Bob 的瀏覽器發向銀行,而這個請求會附帶 Bob 瀏覽器中的 cookie 一起發向銀行服務器。大多數情況下,該請求會失敗,因為他要求 Bob 的認證信息。但是,如果 Bob 當時恰巧剛訪問他的銀行后不久,他的瀏覽器與銀行網站之間的 session 尚未過期,瀏覽器的 cookie 之中含有 Bob 的認證信息。這時,悲劇發生了,這個 url 請求就會得到響應,錢將從 Bob 的賬號轉移到 Mallory 的賬號,而 Bob 當時毫不知情。等以后 Bob 發現賬戶錢少了,即使他去銀行查詢日志,他也只能發現確實有一個來自於他本人的合法請求轉移了資金,沒有任何被攻擊的痕跡。而 Mallory 則可以拿到錢后逍遙法外。

Django 提供的 CSRF 防護機制

  django 第一次響應來自某個客戶端的請求時(get方式),會在服務器端隨機生成一個 token,然后把這個 token 寫在用戶請求的 cookie 里,同時也會給客戶端頁面發送一個隨機的 token (form表單中以{% csrf_token %}方式獲取)用以認證。之后客戶端每次以 POST 方式向服務端提交請求時,都會帶上這個 token,這樣就能避免被 CSRF 攻擊。

  1.在返回的 HTTP 響應的 cookie 里,django 會為你添加一個 csrftoken 字段,其值為一個自動生成的 token;
  2.在所有的 POST 表單中,必須包含一個 csrfmiddlewaretoken 字段 (只需要在模板里加一個 tag, django 就會自動幫你生成,見下面)
  3.在處理 POST 請求之前,django 會驗證這個請求的 cookie 里的 csrftoken 字段的值和提交的表單里的 csrfmiddlewaretoken 字段的值是否一樣。如果一樣,則表明這是一個合法的請求,否則,這個請求可能是來自於別人的 csrf 攻擊,返回 403 Forbidden.
  4.在所有 ajax POST 請求里,添加一個 X-CSRFTOKEN header,其值為 cookie 里的 csrftoken 的值

Django 里如何使用 CSRF 防護

  首先,最基本的原則是:GET 請求不要用!有副作用!也就是說任何處理 GET 請求的代碼對資源的訪問都一定要是“只讀“的;
  其次,要啟用 django.middleware.csrf.CsrfViewMiddleware 這個中間件;
  最后,在所有的 POST 表單元素中,需要加上一個 {% csrf_token %} tag。原因:用於csrf在模版渲染過程中,會自動為表單添加一個名為 csrfmiddlewaretoken , type屬性為 hidden 的 input。

Django CSRF 應用<基本應用,FBV和CBV不同,ajax應用>

a. 基本應用:
			直接在form表單中添加:就能應用。
			{% csrf_token %} -----> 轉換成一個hidden屬性的input標簽
			{{ csrf_token }} -----> 直接獲取csrf的隨機字符串
			
			注意:本地的cookies中也會添加隨機字符串 ---> 注意key名
		
	b. 全站禁用:
		- 整個框架不使用csrf安全機制,直接在settings.py文件中注銷,整個網站都不再應用。
		# 'django.middleware.csrf.CsrfViewMiddleware',
	
	c. 局部禁用:全局使用,但是某些函數不需要應用。
		- settings.py文件中不注銷,在項目的views.py函數中導入模塊,給函數或是類加上對應方法的裝飾器:
		'django.middleware.csrf.CsrfViewMiddleware',
		
		from django.views.decorators.csrf import csrf_exempt,csrf_protect

		@csrf_exempt   #不再做檢測!其他沒加裝飾器的函數還是會檢測
		def csrf1(request):

			if request.method == 'GET':
				return render(request,'csrf1.html')
			else:
				return HttpResponse('ok')
	
	d. 局部使用:全局不使用,但是某些函數需要應用。
		
		# 'django.middleware.csrf.CsrfViewMiddleware',
		
		from django.views.decorators.csrf import csrf_exempt,csrf_protect

		@csrf_protect  #全站不用,某個函數需要使用認證的時候
		def csrf1(request):

			if request.method == 'GET':
				return render(request,'csrf1.html')
			else:
				return HttpResponse('ok')
		
	e. 特殊CBV:在CBV應用中,有些特殊!
		django 不認給類內的函數名上添加裝飾器,只能是在類上添加。
		同時django限制若是應用裝飾器,必須用它的方法去添加,同時添加的語法格式也有限制。
		
			from django.views import View
			from django.utils.decorators import method_decorator  #必須使用這個方法
				- 語法:@method_decorator(裝飾器函數名稱或方法,name='被裝飾的函數名')

			#先導入方法,然后裝飾器以參數的形式添加,其次指定要添加這個方法的函數名<樣式:name="函數名">
					
			@method_decorator(csrf_protect,name='dispatch')
			class Foo(View):
				#請求來了,都是先執行類View的內置函數dispatch,然后再映射到對應的方法上!
				#所以給dispatch添加上就相當於給所有的方法添加了
				def get(self,request):
					pass

				def post(self,request):
					pass
		
		PS:CBV中添加裝飾器 
			#自定義的裝飾器
			def wrapper(func):
				def inner(*args,**kwargs):
					return func(*args,**kwargs)
				return inner
			
			# 1. 指定方法上添加裝飾器
					class Foo(View):
						@method_decorator(wrapper)    #先導入方法,然后裝飾器以參數的形式添加
						def get(self,request):
							pass
								
						def post(self,request):
							pass
			# 2. 在類上添加
				    @method_decorator(wrapper,name='dispatch') 
				    class Foo(View):
				        def get(self,request):
				            pass
				        def post(self,request):
				            pass
			
		
	f.Ajax提交數據時候,攜帶CSRF:
		a. 以post方式提交,放置在data中攜帶
		
			<form method="POST" action="/csrf1.html">
				{% csrf_token %}
				<input id="user" type="text" name="user" />
				<input type="submit" value="提交"/>
				<a onclick="submitForm();">Ajax提交</a>
			</form>
			<script src="/static/jquery-1.12.4.js"></script>
			<script>
				function submitForm(){
					var csrf = $('input[name="csrfmiddlewaretoken"]').val();
					var user = $('#user').val();
					$.ajax({
						url: '/csrf1.html',
						type: 'POST',
						data: { "user":user,'csrfmiddlewaretoken': csrf},  
							        #注意csrf隨機字符串,后台有固定的名字接收,這種方式是通過標簽獲取的對應值      

              
                    
                            success:function(arg){ console.log(arg); } }) } </script>
b. POST方式提交,信息放在請求頭中,從cookies中獲取的csrf隨機字符串 <form method="POST" action="/csrf1.html"> {% csrf_token %} <input id="user" type="text" name="user" /> <input type="submit" value="提交"/> <a onclick="submitForm();">Ajax提交</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script src="/static/jquery.cookie.js"></script> <script> function submitForm(){ var token = $.cookie('csrftoken'); var user = $('#user').val(); $.ajax({ url: '/csrf1.html', type: 'POST', headers:{'X-CSRFToken': token}, #注意csrf隨機字符串后台有固定的名字接收 data: { "user":user}, success:function(arg){ console.log(arg); } }) } </script>

django csrf注意點:

注意一定注意:ajax POST提交的時候,csrf-token 隨機字符串 直接放在data數據中的方式為:data:{csrfmiddlewaretoken:"{{ csrf_token }}"}

 

  若是導入自己寫的JS文件,那上述方法就不能獲取到Django后台發送的隨機字符串,而是需要利用上面介紹的兩種方式獲取(頁面寫上{% csrf_token %},通過隱藏的input標簽取value值寫在POST提交的data數據中;或是從cookie中獲取,寫在頭文件中。)

使用django框架時:
  每次初始化一個項目時都要看看 django.middleware.csrf.CsrfViewMiddleware 這個中間件
  每次在模板里寫 form 時都需要加一個 {% csrf_token %} tag
  每次發 ajax POST 請求,都需要加一個 X_CSRFTOKEN 的 header
流程:
  用戶第一次訪問頁面,肯定是get請求,此時服務端就會給客戶端發送一段隨機字符串的數據,當客戶提交數據的時候,常在POST請求中帶回,就會發送隨機字符串給服務端(上一次請求獲取的數據)用於驗證。
  服務端給客戶端發送的隨機字符串作為一種安全機制,客戶端往服務端發送請求時再攜帶回來,用於匹配認證。
  可以從form表單中接收,也可以在cookies中查看,注意:這兩個的隨機字符串是不同的!
  如果開啟了csrf認證,后台沒有拿到對應的字符串的話就會報錯---> 403


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM