Django:模板template(二)
將跨站請求偽造和驗證碼的東西記一下
CSRF
Cross Site Request Forgery。跨站請求偽造
鏈接:GET請求;表單:POST請求
某些惡意的網站上,包含鏈接、表單、按鈕、JavaScript。利用用戶在瀏覽器上的認證信息試圖在網站上完成某些操作,稱為CSRF(跨站請求偽造)
例子:
設計兩個頁面,一個用於提交請求(POST),一個用於展示請求提交的數據
booktest/urls.py
urlpatterns = [ url(‘^csrf1$‘,views.csrf1, name="csrf1"), url(‘^csrf2$‘,views.csrf2, name="csrf2"), ]
booktest/views.py
def csrf1(request): context = {} return render(request, ‘booktest/csrf1.html‘, context) def csrf2(request): uname = request.POST[‘uname‘] context = {‘uname‘: uname} return render(request, ‘booktest/csrf2.html‘, context)
templates/booktest/csrf1.html
<body> <form method="post" action="/booktest/csrf2"> <input type="text" name="uname"/> <input type="submit" value="提交"/> </form> </body>
templates/booktest/csrf2.html
<body> {{ uname }} </body>
輸入姓名,點擊提交按鈕,會出現如下效果
出現這個是因為django默認使用了
django4/settings.py
MIDDLEWARE_CLASSES = ( ‘django.contrib.sessions.middleware.SessionMiddleware‘, ‘django.middleware.common.CommonMiddleware‘, #‘django.middleware.csrf.CsrfViewMiddleware‘, ‘django.contrib.auth.middleware.AuthenticationMiddleware‘, ‘django.contrib.auth.middleware.SessionAuthenticationMiddleware‘, ‘django.contrib.messages.middleware.MessageMiddleware‘, ‘django.middleware.clickjacking.XFrameOptionsMiddleware‘, ‘django.middleware.security.SecurityMiddleware‘, )
改成發布模式
django4/settings.py
DEBUG = False ALLOWED_HOSTS = [‘*‘]
然後,啟動服務器。需要帶上IP地址
python manage.py runserver 192.168.30.2:8080
此時,在瀏覽器上訪問服務器的時候,輸入的URL是 http://192.168.30.2:8080/booktest/csrf1
註意:現在是真實訪問服務器的場景。
任意提交數據,都可以在csrf2中顯示(比如嵌入一段html代碼)
<script> for(;;) alert(123); </script>
另外,還有一種可能。現在訪問服務器上的URL http://192.168.30.2:8080/booktest/csrf1 獲得一個網頁的時候,可以把網頁的源碼摳下來。
MIDDLEWARE_CLASSES = ( ‘django.contrib.sessions.middleware.SessionMiddleware‘, ‘django.middleware.common.CommonMiddleware‘, ‘django.middleware.csrf.CsrfViewMiddleware‘, ‘django.contrib.auth.middleware.AuthenticationMiddleware‘, ‘django.contrib.auth.middleware.SessionAuthenticationMiddleware‘, ‘django.contrib.messages.middleware.MessageMiddleware‘, ‘django.middleware.clickjacking.XFrameOptionsMiddleware‘, ‘django.middleware.security.SecurityMiddleware‘, )
但是禁止了CSRF結果就會連自己都無法訪問了(http://192.168.30.2:8080/booktest/csrf1 )所以不能這樣做。
防止跨域攻擊的方法:在csrf1.html中,在表單中添加一個標簽
<body> <form method="post" action="/booktest/csrf2"> {% csrf_token %} <input type="text" name="uname"/> <input type="submit" value="提交"/> </form> </body>
此時,訪問http://192.168.30.2:8080/booktest/csrf1 的時候,查看源碼,會發現表單中多了一項
這個就是CSRF的保護措施了
此時,只有在服務器的URL http://192.168.30.2:8080/booktest/csrf1 給 http://192.168.30.2:8080/booktest/csrf2 發送請求,才能接收。而在本地的URL file:///D:/gz1833_python/20180918/test.html 給http://192.168.30.2:8080/booktest/csrf2 發送請求,則會有403的錯誤(Forbidden CSRF verification failed)。
驗證碼
驗證碼的作用:防爬蟲、減輕服務器的壓力、防CSRF
原理:畫一張圖。圖片上隨機輸出幾個字。要求登錄的人輸入值要和圖片隨機生成的值一致
首先,我們要讓服務器返回一張圖片,需要安裝一個庫pillow
pip install pillow
安裝後在python終端嘗試:
from PIL import Image, ImageDraw, ImageFont # Image:畫布 # ImageDraw:畫筆 # ImageFont:字體(推薦使用一個字體庫FreeFont) # 註意:訪問服務器的圖片,響應頭中的MIME類型必須為image/png或image/jpeg(之前都是text/html)
編寫返回圖片驗證碼的代碼
booktest/urls.py
urlpatterns = [ url(‘^verifyCode$‘,views.verifyCode, name="verifyCode"), ]
booktest/views.py
def verifyCode(request): from PIL import Image, ImageDraw, ImageFont import random # 規定寬高 寬和高的比例決定驗證碼的長度是多少 這裏是100/25=4 width = 100 height = 25 # 背景色 bgColor = (63,63,63) # 較深 # 創建畫布 # 參數1 mode 模式 RGB # 參數2 size 長度為2的元組 (width, height) # 參數3 color 畫布的背景色 長度為3的元組 (R,G,B) image = Image.new(‘RGB‘, (width, height), bgColor) # 創建畫筆 # 參數1 im 畫布對象 # 參數2 mode 模式 默認為None draw = ImageDraw.Draw(image) # 創建字體 # 參數1 font 字體文件 # 參數2 字體大小 font = ImageFont.truetype(‘FreeMono.ttf‘, 24) # 文字 text = ‘0123456789‘ textTemp = ‘‘ # 逐個描繪字符 for i in range(4): textTemp1 = text[random.randrange(0,len(text))] textTemp += textTemp1 # 使用畫筆對象在畫布上描繪字符 # 參數1 xy 要描繪的字符左上角的坐標 長度為2的元組 # 參數2 text 要描述的字符 # 參數3 fill 要描述的字符的顏色 # 參數4 font 字體 draw.text((i*25,0), textTemp1, (255,255,255), font) print(textTemp) # 把畫布保存到內存中 #import cStringIO # python2的內存庫 import io # python3中的內存庫 buf = io.BytesIO() image.save(buf, ‘png‘) # 將內存流中的內容輸出到客戶端 return HttpResponse(buf.getvalue(), ‘image/png‘)
接下來在網頁上顯示驗證碼
booktest/urls.py
urlpatterns = [ url(‘^verifyCode$‘,views.verifyCode, name="verifyCode"), url(‘^verifyTest$‘,views.verifyTest, name="verifyTest"), ]
booktest/views.py
def verifyTest(request): context = {} return render(request, ‘booktest/verifyTest.html‘, context)
templates/booktest/verifyTest.html
<body> <form method="post" action="/booktest/verifyTest2"> {% csrf_token %} 姓名:<input type="text" name="uname"/><br/> 驗證碼:<input type="text" name="verifycode"/><img src="/booktest/verifyCode"><br/> <input type="submit" value="提交"/> </form> </body>
在verifyCode中,把隨機產生的驗證碼保存到session中
booktest/views.py
def verifyCode(request): from PIL import Image, ImageDraw, ImageFont ... ... print(textTemp) # 保存到session中 request.session[‘code‘] = textTemp # 把畫布保存到內存中 ... ...
添加路由
booktest/urls.py
urlpatterns = [ url(‘^verifyTest2$‘,views.verifyTest2, name="verifyTest2"), ]
booktest/views.py
def verifyTest2(request): ori_code = request.session[‘code‘] post_code = request.POST[‘verifycode‘] print(‘ori_code:%s, post_code:%s‘ % (ori_code, post_code)) if ori_code == post_code: return HttpResponse(‘ok‘) else: return HttpResponse(‘fail‘)
訪問 http://127.0.0.1:8080/booktest/verifyTest 提交正確/錯誤驗證碼,後臺可以自行檢查了。
Django:模板template(二)