nodejs之cookie和session

由于最近工作需要又将node捡了起来。翻了下之前的笔记,想着把几篇比较详细的整理下分享出来。第一篇就来说说经常会用到的cookie&session。

由来

众所周知http是一个无状态的协议,服务端无法跟踪客户端的状态。那么就会导致一个问题,如我们以管理员身份登录一个后台管理系统,登录成功后跳转到管理页面,那在我们进行操作时,服务器怎么知道我们是否已经登录过了呢?

cookie

为了解决上面的问题,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的读取和设置都很简单,设置的时候有一些可选参数,

  • domain:存储的域名,cookie是不跨域的,并且存储在主域名中子域名是可以访问到的,但是如果存在子域名中那么主域名是无法访问的。所以这里一般是存在主域名,避免子域名访问不到cookie。
  • path:存储路径,与domain类似,所以一般也是指定根路径。
  • maxAge:有效期(毫秒)

运行下代码,然后到浏览器中查看刚刚写入的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');
})
  • httpOnly:设置cookie只能由服务器操作,前台看不到
  • secure:只有在https的情况下才能使用cookie
  • singed:设置cookie是否签名

这里我先现开启签名。然后运行代码
在这里插入图片描述
可以看到这回的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的存储空间,所以我们只签名重要的信息。

session

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)

阅读 257

推荐阅读