CSRF(Cross-site request forgery),中文名稱:跨站請求僞造。攻擊者盜用你的身份,以你的名義發送惡意請求。CSRF可以作的事情包括:以你名義發送郵件,發消息,盜取你的帳號,甚至於購買商品,虛擬貨幣轉帳......形成的問題包括:我的隱私泄露以及財產安全。javascript
一、token驗證方法html
(1)、CSRF 攻擊之因此可以成功,是由於黑客能夠徹底僞造用戶的請求,該請求中全部的用戶驗證信息都是存在於 cookie 中,所以黑客能夠在不知道這些驗證信息的狀況下直接利用用戶本身的 cookie 來經過安全驗證。要抵禦 CSRF,關鍵在於在請求中放入黑客所不能僞造的信息,而且該信息不存在於 cookie 之中。能夠在 HTTP 請求中以參數的形式加入一個隨機產生的 token,並在服務器端創建一個攔截器來驗證這個 token,若是請求中沒有 token 或者 token 內容不正確,則認爲多是 CSRF 攻擊而拒絕該請求。前端
(2)、這種方法要比檢查 Referer 要安全一些,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。java
(3)、該方法還有一個缺點是難以保證 token 自己的安全。特別是在一些論壇之類支持用戶本身發表內容的網站,黑客能夠在上面發佈本身我的網站的地址。因爲系統也會在這個地址後面加上 token,黑客能夠在本身的網站上獲得這個 token,並立刻就能夠發動 CSRF 攻擊。爲了不這一點,系統能夠在添加 token 的時候增長一個判斷,若是這個連接是鏈到本身本站的,就在後面添加 token,若是是通向外網則不加。不過,即便這個 csrftoken 不以參數的形式附加在請求之中,黑客的網站也一樣能夠經過 Referer 來獲得這個 token 值以發動 CSRF 攻擊。這也是一些用戶喜歡手動關閉瀏覽器 Referer 功能的緣由。程序員
二、token產生ajax
Token是在服務端產生的。若是前端使用用戶名和密碼向服務端發送請求認證,服務端認證成功,那麼在服務端會返回Token給前端。前端能夠在每次請求的時候帶上Token證實本身的合法地位。若是Token在服務端持久化,那他就是一個永久的身份令牌。spring
三、Token設置有效期json
Q: 用戶在正常操做的過程當中,Token 過時失效了,要求用戶從新登陸……用戶體驗會很糟糕。segmentfault
A: 方法一,使用 Refresh Token。這種方法中,服務端不須要刷新 Token 的過時時間,一旦 Token 過時,就反饋給前端,前端使用 Refresh Token 申請一個全新 Token 繼續使用。這種方法中,服務端只須要在客戶端請求更新 Token 的時候對 Refresh Token 的有效性進行一次檢查,大大減小了更新有效期的操做,也就避免了頻繁讀寫。固然 Refresh Token 也是有有效期的,可是這個有效期就能夠長一點了,好比,以天爲單位的時間。api
(1)、實例以下:
//通常是登陸時向服務器發請求獲取到Token function login(username,password){ var param = {"username":username,"password":password}; $.post("/api/v1/login",param,function(data){ //將response獲得的Token緩存到sessionStorage裏面 sessionStorage.setItem('Token',data.TOKEN); }).error(function(error){ alert(JSON.parse(error.responseText).errorMsg); }) } //登陸事件 $("#login").click(function(){ var username=$('input[name=username]').val(); var password=$('input[name=password]').val(); login(username,password); })
(2)、token請求驗證:
客戶端拿sessionStorage中存儲的Token去向服務端進行驗證:
function ajaxRequest = function(option) { $.ajax({ url: getDmsFuncIdUrl(newUrl, currentToken), type: option.type, data: option.data, dataType: "json", async: option.async != undefined ? option.async : true, cache: false, beforeSend: function(xhr) { xhr.setRequestHeader("Accept", "application/json;charset=UTF-8"); //設置數據格式:發送json格式數據,並帶有字符編碼:"charset=UTF-8" xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); //將Token放在請求頭header中,此處格式與後臺一一對應。 xhr.setRequestHeader( "Authorization", "Bearer " + getParamsStorage("Token") ); if (option.beforeSend) { option.beforeSend(xhr); } }, success: function(data, textStatus, jqXHR) { //結束ajax請求 ajaxRestEnd(option); }, error: function(XMLHttpRequest, textStatus, errorThrown) { //結束ajax請求 ajaxRestEnd(option); } }) };
以下圖:
(3)、總結:
這樣咱們每次的請求都調用 ajaxRequest 方法便可,即在每次請求接口數據的的時候都會帶上咱們登錄後得到的Token值,這樣就能經過服務器的驗證,打開服務器的大門,進而進行不一樣接口數據的調用啦!是否是很清楚呢~~~
(4)、Refresh Token
通常是在獲取頁面的公共經常使用數據的時候刷新Token值
//刷新Token function refreshToken() { dmsCommon.ajaxRestRequest({ url:"/api/v1/login/refreshToken", type: "GET", async: false, sucessCallBack: function(data) { currentToken = data; } }); } //每5分鐘刷新一次token 值 function refreshTokenInterval() { setInterval(refreshToken, 5 * 60 * 1000); } //初始化常規數據 function getMainnData(){ // coding //進行定時刷新 refreshTokenInterval(); }
借鑑大牛的文章,淺顯易懂, URL: https://segmentfault.com/a/11...