由于最近工作需要又将node捡了起来。翻了下之前的笔记,想着把几篇比较详细的整理下分享出来。第一篇就来说说经常会用到的cookie&session。
众所周知http是一个无状态的协议,服务端无法跟踪客户端的状态。那么就会导致一个问题,如我们以管理员身份登录一个后台管理系统,登录成功后跳转到管理页面,那在我们进行操作时,服务器怎么知道我们是否已经登录过了呢?
为了解决上面的问题,cookie诞生了。
cookie是http协议中的一部分,浏览器向服务器发请求,成功后服务器向浏览器返回一个cookie,那么以后浏览器向服务器发送的所有请求都会携带这个cookie。
首先安装express框架,当然你也可以使用koa。这里演示代码都是express。
在express中cookie不是自带的,所以需要安装对应的中间件进行操作,koa中的cookie就是框架自带的就不需要另外安装。
安装cookie-parser中间件
npm i cookie-parser -D
写cookie
安装成功后,先引入cookie-parser。然后在任意路由中去尝试写一个cookie
const express = require('express');
const cookieParser = require('cookie-parser');
let server = express();
server.listen(8080);
// 使用中间件
server.use(cookieParser());
server.get('/index',(req, res) => {
// 使用了中间件后就可以访问req和res上的cookies对象
console.log(req.cookies);
// 写cookie
res.cookie('num', 10, {
// domain: 'xxx.com',
// path: '/',
maxAge: 24 * 3600 * 1000
})
res.send('ok');
})
cookie的读取和设置都很简单,设置的时候有一些可选参数,
运行下代码,然后到浏览器中查看刚刚写入的cookie
打开浏览器F12,到Application中找到Cookies,就可以看到刚刚写入的cookie,名字和值以及有效期都是我们设置的。再次刷新后我们也可以在命令行中看到服务器打印的cookie。
简单的cookie读写就完成了。
安全隐患
这里我们可以知道cookie是存在浏览器中的,并且请求服务器的时候会一并带过去。这样就一定会有安全隐患,我们先把服务器写cookie的逻辑注释掉,重新运行服务器,然后尝试在浏览器中手动修改cookie。
这里我们将值修改为10000。刷新页面后在命令行中可以看到服务器获取的值就是10000。
cookie就这样很容易的在浏览器中被我们修改了。如果cookie存了一些比较重要的数据,后果会非常严重。
cookie签名
怎么样才能做到让服务器验证cookie准确性,让服务器发现cookie是否被人为修改。
就要用到cookie签名。修改下服务器代码。
// 密钥
server.use(cookieParser(
'dasdasdasdasfewg315nkl23k1ml41m24kl1nm5kol312n5kl32n5oj3n4oi1jm4o1k2m4'
));
在使用cookieParser中间件的时候加入一个签名密钥,一般是随机生成的一个字符串
然后在设置cookie的时候加入几个参数。
server.get('/index',(req, res) => {
// 签名后的cookie需要通过signedCookies访问
console.log(req.signedCookies);
res.cookie('num', 10, {
// httpOnly: true,
// secure: true,
signed: ture
maxAge: 24 * 3600 * 1000
})
res.send('ok');
})
这里我先现开启签名。然后运行代码
可以看到这回的cookie是一串乱码。将乱码复制出来是这样的。
s%3A10.y4%2BaUbiQxjUS%2FvaGtU%2BaZnAZ9WxVHXy3O0zr%2BgoCdGk
%3A代表":",转换下得到如下:
s:10.y4%2BaUbiQxjUS%2FvaGtU%2BaZnAZ9WxVHXy3O0zr%2BgoCdGk
通过以上得出签名后的cookie格式为:
s:值.签名
这样如果我们尝试修改其中的值,还会不会生效了呢?
将服务器设置cookie的代码注释掉,只打印cookie,然后在浏览器中修改cookie。
修改后的cookie因为无法通过服务器的签名验证,所以是无法获取的。这样就确保了cookie的安全性,虽然签名可以增加cookie的安全性,但是增大体积,由于cookie只有4k的存储空间,所以我们只签名重要的信息。
cookie 虽然很方便,但是使用 cookie 有一个很大的弊端,就是存储在浏览器,虽说可以对cookie进行签名,但是也不能保证cookie的绝对安全,并且将重要的信息存在客户端本身就是不安全的事情。同时cookie也受限于大小。为了解决这些问题session也诞生了。
session 中的数据是保留在服务器端的。session不会单独存储,会有标识,这个标识叫做session_id 或者 token。并且session是强制加密的。
同样我们需要另一个中间件操作session,cookie-session
npm i cookie-session -D
使用方式与cookie-parser类似,先引入cookie-session
const cookieSession = require('cookie-session');
然后进行循环密钥签名,密钥一般是通过程序生成的,可能几千几万条,这里方便演示,只写几条。
server.use(cookieSession({
keys: ['dasdas21fsdffedsfds4das21321', 'safdas454325235325trgtrthdfthd', '21ed2rf3245r23r2354r235235'],
maxAge: 20 * 60 * 1000 // 有效期20分钟
}));
然后在接口中设置和获取session
server.get('index', (req, res) => {
console.log(req.session);
res.session['num'] = 10;
res.send('ok');
});
运行代码,打开浏览器调试工具找到cookies,
cookie中有两个值,一个是session,一个是session.sig
将服务器中设置session的代码注释掉,再刷新页面,可以看到命令行中就打印了我们设置的session值。
就算其他用户通过session劫持拿到了我们的session值,但是每个用户的session.sig签名是通过循环密钥生成的,数量庞大的循环密钥相同的几率很小。并且在浏览器手动修改session后,服务器也会感知到这个session和session.sig不是对应的。确保数据的安全性。同时也可以通过更换循环密钥和减少session有效期来提升安全性。
需要注意的是session是存在服务器的文件中。读写比较消耗性能。我们可以将其保存在redis、内存、数据库中以优化性能。(如使用mysql-session)