1、須要向web頁面注入惡意代碼;javascript
2、這些惡意代碼可以被瀏覽器成功的執行。html
解決辦法:前端
一、一種方法是在表單提交或者url參數傳遞前,對須要的參數進行過濾。
二、在後臺對從數據庫獲取的字符串數據進行過濾,判斷關鍵字。
三、設置安全機制。
django框架:內部機制默認阻止了。它會斷定傳入的字符串是不安全的,就不會渲染而以字符串的形式顯示。若是手賤寫了safe,那就危險了,若想使用safe,那就必須在後臺對要渲染的字符串作過濾了。因此在開發的時候,必定要慎用安全機制。尤爲是對用戶能夠提交的並能渲染的內容!!!java
- 示例:web
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 <form method="POST" action="/comment/"> 9 <h4>評論</h4> 10 <input type="text" name="content"/> 11 <input type="submit" value="提交" />{{ error }} 12 </form> 13 </body> 14 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 <h1>評論內容</h1> 9 {% for item in msg %} 10 <div>{{ item|safe }}</div> 11 {% endfor %} 12 </body> 13 </html>
1 from django.shortcuts import render 2 msg = [] 3 def comment(request): 4 if request.method == "GET": 5 return render(request,'comment.html') 6 else: 7 v = request.POST.get('content') 8 if "script" in v: 9 return render(request,'comment.html',{'error': '小比崽子還黑我'}) 10 else: 11 msg.append(v) 12 return render(request,'comment.html') 13 14 def index(request): 15 return render(request,'index.html',{'msg':msg}) 16 17 def test(request): 18 from django.utils.safestring import mark_safe 19 temp = "<a href='http://www.baidu.com'>百度</a>" 20 newtemp = mark_safe(temp) 21 return render(request,'test.html',{'temp':newtemp}
什麼是 CSRFajax
CSRF, Cross Site Request Forgery, 跨站點請求僞造。舉例來說,某個惡意的網站上有一個指向你的網站的連接,若是某個用戶已經登陸到你的網站上了,那麼當這個用戶點擊這個惡意網站上的那個連接時,就會向你的網站發來一個請求,你的網站會覺得這個請求是用戶本身發來的,其實呢,這個請求是那個惡意網站僞造的。數據庫
1.用戶C打開瀏覽器,訪問受信任網站A,輸入用戶名和密碼請求登陸網站A;django
2.在用戶信息經過驗證後,網站A產生Cookie信息並返回給瀏覽器,此時用戶登陸網站A成功,能夠正常發送請求到網站A;json
3.用戶未退出網站A以前,在同一瀏覽器中,打開一個TAB頁訪問網站B;後端
4.網站B接收到用戶請求後,返回一些攻擊性代碼,併發出一個請求要求訪問第三方站點A;
5.瀏覽器在接收到這些攻擊性代碼後,根據網站B的請求,在用戶不知情的狀況下攜帶Cookie信息,向網站A發出請求。網站A並不知道該請求實際上是由B發起的,因此會根據用戶C的Cookie信息以C的權限處理該請求,致使來自網站B的惡意代碼被執行。
csrf的攻擊之因此會成功是由於服務器端身份驗證機制能夠經過Cookie保證一個請求是來自於某個用戶的瀏覽器,但沒法保證該請求是用戶容許的。所以,預防csrf攻擊簡單可行的方法就是在客戶端網頁上添加隨機數,在服務器端進行隨機數驗證,以確保該請求是用戶容許的。Django也是經過這個方法來防護csrf攻擊的。
在客戶端頁面上添加csrftoken, 服務器端進行驗證,服務器端驗證的工做經過'django.middleware.csrf.CsrfViewMiddleware'這個中間層來完成。在django當中防護csrf攻擊的方式有兩種, 1.在表單當中附加csrftoken 2.經過request請求中添加X-CSRFToken請求頭。注意:Django默認對全部的POST請求都進行csrftoken驗證,若驗證失敗則403錯誤侍候。
後端
1 from django.shortcuts import render 2 from django.template.context_processors import csrf 3 4 def ajax_demo(request): 5 # csrf(request)構造出{‘csrf_token’: token} 6 return render(request, 'post_demo.html', csrf(request))
前端
1 $('#send').click(function(){ 2 3 $.ajax({ 4 type: 'POST', 5 url:'{% url 'ajax:post_data' %}', 6 data: { 7 username: $('#username').val(), 8 content: $('#content').val(), 9 'csrfmiddlewaretoken': '{{ csrf_token }}' 關鍵點 10 }, 11 dataType: 'json', 12 success: function(data){ 13 14 }, 15 error: function(){ 16 17 } 18 19 }); 20 });
後端
該方式須要藉助於Cookie傳遞csrftoken, 設置Cookie的方式有兩種。ps:經測試即使什麼都不作,也會設置Cookie,不過官方文檔說,不保證每次都有效
1.表單中添加{%csrf_token%}這個模板標籤
1 <form id="comment_form" action="#"></form> 2 {% csrf_token %} 就是這個 3 <p>姓名: <input type="text" name="useranme" id="username"></p> 4 <p>內容: <textarea name="content" id="content" rows="5" cols="30"></textarea></p> 5 <p><input type="button", id="send" value="提交"></p>
2.ensure_csrf_cookie裝飾器
1 from django.shortcuts import render 2 from django.views.decorators.csrf import ensure_csrf_cookie 3 4 @ensure_csrf_cookie 5 def ajax_demo(request): 6 return render(request, 'ajax_demo.html')
1 <script type="text/javascript"> 2 $(function(){ 3 4 function getCookie(name) { 5 var cookieValue = null; 6 if (document.cookie && document.cookie != '') { 7 var cookies = document.cookie.split(';'); 8 for (var i = 0; i < cookies.length; i++) { 9 var cookie = jQuery.trim(cookies[i]); 10 // Does this cookie string begin with the name we want? 11 if (cookie.substring(0, name.length + 1) == (name + '=')) { 12 cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 13 break; 14 } 15 } 16 } 17 return cookieValue; 18 } 19 20 <!--獲取csrftoken--> 21 var csrftoken = getCookie('csrftoken'); 22 console.log(csrftoken); 23 24 //Ajax call 25 function csrfSafeMethod(method) { 26 // these HTTP methods do not require CSRF protection 27 return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 28 } 29 30 $.ajaxSetup({ 31 crossDomain: false, // obviates need for sameOrigin test 32 //請求前觸發 33 beforeSend: function(xhr, settings) { 34 if (!csrfSafeMethod(settings.type)) { 35 xhr.setRequestHeader("X-CSRFToken", csrftoken); 36 } 37 } 38 }); 39 40 $('#send').click(function(){ 41 console.log($("#comment_form").serialize()); 42 43 $.ajax({ 44 type: 'POST', 45 url:'{% url 'ajax:post_data' %}', 46 data: { 47 username: $('#username').val(), 48 content: $('#content').val(), 49 //'csrfmiddlewaretoken': '{{ csrf_token }}' 50 }, 51 dataType: 'json', 52 success: function(data){ 53 54 55 }, 56 error: function(){ 57 58 } 59 60 }); 61 }); 62 63 64 }); 65 </script>
經過csrf_exempt, 來取消csrftoken驗證,方式有兩種。
1 .在視圖函數當中添加csrf_exempt裝飾器
1 from django.views.decorators.csrf import csrf_exempt 2 3 @csrf_exempt 4 def post_data(request): 5 pass
2 .在urlconf當中
1 from django.views.decorators.csrf import csrf_exempt 2 urlpatterns = [ 3 url(r'^post/get_data/$', csrf_exempt(post_data), name='post_data'), 4 5 ]
注意必定注意: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