天天看點

java 單頁應用_從單頁應用看node的token(二)

上一篇中,講了下cookie+session的方式check使用者狀态,但是處理CSRF(跨站請求僞造)上會麻煩一點。

既然說到了CSRF,那先稍微解釋一下。

CSRF

csrf是一種攻擊方法,通俗的就是說攻擊者僞裝成你進行行騙。 這種是如何做到的呢?

從原理上說,這種攻擊方式不需要竊取到使用者的cookie,而是直接使用使用者的cookie去進行違法行為。

怎麼做到的?

我模拟一下這種情況:

有一個網站A,A中有個post或get請求,用于對視訊進行點贊。用戶端和服務端的認證是用cookie進行的(參照第一篇的cookie+session的方式)

現在有個網站B,是攻擊者設定的,可能是通過誘惑标題引你進去,抑或是通過通過xss方式往C網站植入了一個iframe,等等,無論哪種設定,都是當你進入相應的B或C頁面時,就會自動去請求A網站那個點贊的接口。

如果我們之前登陸過網站A,并且并沒有登出,那麼請求A網站那個接口時,浏覽器就會用登陸A網站時建立的cookie,去請求(這是浏覽器自身特性)。比如B網站寫了一個

java 單頁應用_從單頁應用看node的token(二)

這時,可就等于是你在點贊了。

這可能會造成一個很大的問題,比如,會讓某個視訊資源點贊數非常高而順序排的非常靠前, 或者是将一個資源标記為舉報,導緻資源下架。

還可能會因為網站的不嚴謹造成更嚴重的資金損失的問題,等等等等。

到這裡,大家可能會看到問題的嚴重性了。前端同學因為之前不需要關注這些問題,當轉到node時,也很容易忽略這類安全問題。

如何防範

如果大家通過上面的例子知道了深層原因,那也就有了大概的防範思路。但是我們作為技術開發者,不能因為有這種問題而強制使用者每次通路後都立即登出,這對使用者是非常不友好的。

對了,那我們就不讓居心不良的人使用cookie通過session讓服務端确定使用者。也就是說,讓其即使在B網站進行A網站的接口請求,A網站服務端并比對不上使用者,導緻登入不成功,那就沒有問題了。

是以,token這種形式就特别适合了。

token

1. token 是什麼

可以從網上搜一下,會看到很多的解釋。我想通俗的說一下,就是在登入成功時,我們産生一段唯一的,不會輕易被解析的字元串,發送到用戶端,用戶端把這個字元串存起來,每次請求時把這段字元串帶着,讓服務端反解。

看到這裡,是不是感覺跟cookie+session的形式差不多? 是的,從原理上來說,是差不多的,隻是token我們一般不把它放在cookie中,會放在比如loaclstorage中,即便壞人想用csrf的方式搞破壞,但是,他拿不到token,是以也就沒法讓服務端認證為登入狀态,他的陰謀也就無法得逞了。

2. 如何做?

第一,在node中生成好token

// 寫一個中間件token-middleware.js

const setting = require('../../config/setting');

const verify = require('../../config/verify');

function tokenMiddleWare(req, res, next) {

let token = req.headers[setting.token.header];

if(token === undefined){

return next();

}else{

// 可以token校驗并将校驗結果儲存至請求頭中

verify.getToken(token).then(data => {

logger.info('校驗的data是:::', data);

req.data = data;

return next();

}).catch(err =>{

logger.error('校驗出現錯誤:', err);

return next();

})

}

}

module.exports = tokenMiddleWare;

複制代碼//setting.js

module.exports = {

token: {

// token密鑰

signKey: '[email protected]@',

// 過期時間300s

signTime: 300,

// 請求頭參數

header: 'authorization',

// 不用校驗的路由

unRoute: [

{url: /\.(jpg|png|css|js)$/, methods: ['GET']}

]

}

}

複制代碼// verify.js

const jwt = require('jsonwebtoken');

const setting = require('./setting');

const verify = {

// 設定token

setToken(username, _id){

return new Promise(resolve => {

let token = jwt.sign(

// 存儲資料,自定義

{username, _id},

// 密鑰

setting.token.signKey,

{expiresIn: setting.token.signTime, algorithm: 'HS256'}

);

resolve(token);

})

},

getToken(token){

return new Promise((resolve, reject) => {

// 處理token字元串

if(!token.split(' ').length){

reject({error: 'The token value is empty'})

}else{

// 解密token并傳回資料

let data = jwt.verify(token.split(' ')[1],setting.token.signKey)

resolve(data)

}

})

}

}

module.exports = verify;

複制代碼

當登入成功時,進行token的設定:

const verify = require('../../config/verify');

// loginInfo.username -> 登入名

// loginInfo.passwd -> 登入密碼

verify.setToken(loginInfo.username, loginInfo.passwd).then(token => {

// 生成token後,傳回給用戶端

res.json({

code: 0,

mesg: 'success',

token

});

});

複制代碼

然後,需要把寫的中間件和express-jwt應用在app.js(你的根檔案)中

const expressJwt = require('express-jwt');

// 加載token中間件

app.use(tokenMiddleware);

// 驗證token是否可用

app.use(expressJwt({

secret: setting.token.signKey,

algorithms: ['HS256'],

credentialsRequired: false, // 允許無token請求

requestProperty: 'auth' // 把解析的值放在req.auth上

})

.unless({

//除了這個path,其他的URL都需要驗證

path: setting.token.unRoute

}));

複制代碼

注意,當使用express-jwt中間件時,需要一個兜底的中間件,來承接解析錯誤、token過期等結果。

如果出現錯誤,我們預設傳回401,是以我們來設定一下。

app.use(function (err, req, res, next) {

// 當驗證token出現問題時,比如對不上,過期等情況,則傳回401

if (err.name === 'UnauthorizedError') {

res.status(401).send(err.message);

}

});

複制代碼

這樣node這一層就處理好了。

注意: 上面自己寫的那個中間件是自己簡單寫的express-jwt功能,是以用express-jwt, 可以不用我寫的那個中間件。

第二,用戶端處理(使用vue)

用戶端,首先要做的,就是儲存服務端傳回的token,我把它儲存到了loaclstorage上。

比如:

res.data.token && localStorage.setItem('authToken', res.data.token);

複制代碼

然後,需要處理每次前端向服務端的請求頭:

// 同樣,還是用axios

// 攔截前端要發出去的請求

axios.interceptors.request.use(config => {

let token = localStorage.getItem('authToken');

if (token) {

config.headers['Authorization'] = 'Bearer ' + token;

}

return config;

},

error => {

console.error('攔截request出現錯誤', error);

});

複制代碼

這樣,每次前端的請求,都會帶着這個Authorization頭,node層拿到并且解析就可以了。

同時需要注意,如果token解析後,傳回401,那麼我們也需要承接,并且轉到登入頁面。

axios.interceptors.response.use(response => {

return response

},

error => {

if(error.response.status === 401) {

router.push('/login');

}

}

);

複制代碼

token需要注意的問題

要想token不被csrf利用,前提是别讓攻擊者通過xss擷取到,是以,需要處理好xss攻擊。

總結

跟cookie+session的基本原理很相近,都是處理http協定無狀态的情況

token通過設定header頭的形式,避開cookie,防止登入相關的cookie被利用

需要注意處理xss,xss是另外一個攻擊方式,但如果被xss了,token也就有危險了

token跟cookie并不是誰替代誰的問題,而是在什麼場景下用什麼更為合适一些。

好了,關于登入的時候涉及到的點和要規避的坑就先寫到這。

希望大家能有所收獲,用1個多小時的看文章和實地開發測試,解決新手可能要3天才能研究透的問題。 如果大家喜歡,别忘了點個贊哈, 哈哈哈

java 單頁應用_從單頁應用看node的token(二)

關于找一找教程網

本站文章僅代表作者觀點,不代表本站立場,所有文章非營利性免費分享。

本站提供了軟體程式設計、網站開發技術、伺服器運維、人工智能等等IT技術文章,希望廣大程式員努力學習,讓我們用科技改變世界。

[從單頁應用看node的token(二)]http://www.zyiz.net/tech/detail-143833.html