csrf(Cross Site Request Forgery, 跨站域請求僞造:CSRF 攻擊容許惡意用戶在另外一個用戶不知情或者未贊成的狀況下,以他的身份執
行操做。javascript
CSRF 攻擊是黑客藉助受害者的 cookie 騙取服務器的信任,可是黑客並不能拿到 cookie,也看不到 cookie 的內容。另外,對於服務器返回的結果,因爲瀏覽器同源策略的限制,黑客也沒法進行解析。所以,黑客沒法從返回的結果中獲得任何東西,他所能作的就是給服務器發送請求,以執行請求中所描述的命令,在服務器端直接改變數據的值,而非竊取服務器中的數據 。黑客沒法獲取cookie和session值更沒法進行解析。html
假如用戶A在某電商網站註冊過而且用戶本地瀏覽器又存在網站服務端頒發給本身的通行證(也就是cookie),那麼對於用戶A來講本身訪問網站而且提交請求購買商品都是暢通無阻,不須要身份驗證。可是黑客B想要利用A的帳戶給本身買東西,用戶B直接訪問電商網站固然沒法實現這一目的,緣由是B沒有A的通行證,想要利用A的帳戶在訪問網站時又不知道A的密碼。那麼B本身建造了一個黑客網站,這個黑客網站中存在跳轉向目標電商網站的黑客url連接,url連接又包含了用戶的請求(假如是A購買了一個iphone X發給某地址,固然這是B想要的地址)。當用戶訪問黑客網站時,點擊黑客連接時,目標網站就會接受到請求,因爲該請求是A的瀏覽器發出的,因此又包含A的cookie,服務端就會將一個iphone X發往B的地址,那麼黑客B的目的就達到了。因此在csrf中黑客B並不知道A的cookie,只是間接利用了cookie,拿着A的通行證瞞過目標網站,實現本身目的。java
黑客網頁存在指向目標站點的連接,直接跳轉程序員
黑客網頁存在,其中xxx就是指向目標站點的連接,而且包含請求,例如 src=」http://goumai.example/withdraw?account=A&goods=iphonex&for=B 」ajax
黑客網頁包含動態加載的JavaScript,存在轉向目標站點的動做。sql
CSRF 攻擊之因此可以成功,是由於黑客能夠徹底僞造用戶的請求,該請求中全部的用戶驗證信息都是存在於 cookie 中,所以黑客能夠在不知道這些驗證信息的狀況下直接利用用戶本身的 cookie 來經過安全驗證。要抵禦 CSRF,關鍵在於在請求中放入黑客所不能僞造的信息,而且該信息不存在於 cookie 之中。能夠在 HTTP 請求中以參數的形式加入一個隨機產生的 token,並在服務器端創建一個攔截器(中間件:django.middleware.csrf.CsrfViewMiddleware)來驗證這個 token,若是請求中沒有 token 或者 token 內容不正確,則認爲多是 CSRF 攻擊而拒絕該請求。django
token 能夠在用戶登錄後產生並放於 session 之中,而後在每次請求時把 token 從 session 中拿出,與請求中的 token 進行比對,但這種方法的難點在於如何把 token 以參數的形式加入請求。對於 GET 請求,token 將附在請求地址以後,這樣 URL 就變成 http://url?csrftoken=tokenvalue。 而對於 POST 請求來講,要在 form 的最後加上 < input type=」hidden」 name=」csrftoken」 value=」tokenvalue」/>,這樣就把 token 以參數的形式加入請求了。可是,在一個網站中,能夠接受請求的地方很是多,要對於每個請求都加上 token 是很麻煩的,而且很容易漏掉,一般使用的方法就是在每次頁面加載時,使用 javascript 遍歷整個 dom 樹,對於 dom 中全部的 a 和 form 標籤後加入 token。這樣能夠解決大部分的請求,可是對於在頁面加載以後動態生成的 html 代碼,這種方法就沒有做用,還須要程序員在編碼時手動添加 token。dom對象以及cookie瀏覽器
<form action="/login/" method="POST"> {# {{ csrf_token }}#} {{ csrf_token }}表示隨機字符串交給服務端經過測試並隱藏在頁面的input中 {% csrf_token %} {# 隨機字符串隱藏在頁面中的<input>中發送給後臺#} <input type="text" name="user"/> <input type="text" name="pwd"/> <input type="submit" value="提交"/> </form>
$(function () { {# 在Ajax請求前設置請求頭#} $.ajaxSetup({ beforeSend: function (xhr, settings) { xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken')); } }); $('#btn').click(function () { $.ajax({ {# 關於ajax中data#} {# 第一個data就是發送給服務端的數據,success裏面的data是服務器返回的數據#} url: '/login', type:'POST', data:{'user':'root', "pwd":'123'}, headers:{'X-CSRFtoken': $.cookie('csrftoken')}, {# 請求頭中不能出現下劃線不然視爲非法#} success: function (data) { console.log(data); alert(data); }, error: function (data) { alert(data); } } ) }) });
對於Ajax提交時一般還須要對提交請請求的方法進行判斷若是是get,head,options,trace方法,不會改變數據,CSRF 攻擊
沒法解析服務器返回的結果,無需保護。則不須要進行攜帶csrftoken因此請求前須要進行判斷、安全
<script type="text/javascript"> var csrftoken = $.cookie('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); } } }); function Do(){ $.ajax({ url:"/app01/test/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } </script>
xss攻擊服務器
更多請參考
CSRF攻擊與防護