天天看点

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