Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Express教程05:Cookie #72

Open
chencl1986 opened this issue May 9, 2019 · 0 comments
Open

Express教程05:Cookie #72

chencl1986 opened this issue May 9, 2019 · 0 comments

Comments

@chencl1986
Copy link
Owner

阅读更多系列文章请访问我的GitHub博客,示例代码请访问这里

Cookie介绍

Cookie存储在浏览器,在浏览器请求服务器时,其中的数据都会被发送到服务端,常用来做用户信息校验等。

但由于Cookie存储在浏览器,容易受到篡改,安全性较差。

使用cookie-parser处理Cookie

处理Cookie,可以使用中间件cookie-parser

读取Cookie

示例代码:/lesson05/server.js

使用cookie-parser中间件时,需要先通过server.use(cookieParser())解析cookie,之后就可以在req.cookies属性中读取到cookie的值。

在浏览器打开http://localhost:8080/cookie,在控制台写入cookie{"userName":"lee"}

// 使用cookie-parser中间件,解析Cookie
server.use(cookieParser())

server.get('/cookie', (req, res, next) => {
  // 读取cookieParser解析的Cookie
  console.log(req.cookies)

  res.send(`cookies: ${JSON.stringify(req.cookies)}`)
})

在浏览器打开http://localhost:8080/cookie,服务端打印结果为:{"userName":"lee"}

设置Cookie

示例代码:/lesson05/server.js

设置Cookie可以用Express自带的方法res.cookie

方法的第一个参数为设置的属性名,第二个参数为属性值,第三个参数为配置项,例如:

server.get('/cookie', (req, res, next) => {
  // express自带的设置Cookie方法
  res.cookie('userName', 'lee', {
    // 设置该Cookie只可以由服务端访问,即前端JavaScript无法访问document.cookie获取该值,但控制台还是可以查看和修改
    httpOnly: true,
    // 只有通过HTTPS请求的Cookie才被使用,否则都认为是错误的Cookie
    // secure: true,
    // 设置保存Cookie的域名,浏览器查找Cookie时,子域名(如translate.google.com)可以访问主域名(google.com)下的Cookie,而主域名(google.com)不可以访问子域名(如translate.google.com)下的Cookie
    // 本地测试可直接设置为localhost
    domain: 'localhost',
    // 设置保存Cookie的路径,浏览器查找Cookie时,子路径(如/map)可以访问根路径('/')下设置的Cookie,而根路径('/')无法访问子路径(如/map)下设置的Cookie
    path: '/',
    // 通过expires设置Cookie过期时间为14天后
    // expires: new Date(new Date().getTime() + 14 * 86400000),
    // 通过maxAge设置Cookie过期时间为14天后
    maxAge: 14 * 86400000,
  })

  // 读取cookieParser解析的Cookie
  console.log(req.cookies)

  res.send(`cookies: ${JSON.stringify(req.cookies)}`)
})

在浏览器的控制台中,可以看到设置的Cookie为{"userName":"lee"},有效期是14天。

Cookie的签名

示例代码:/lesson05/server.js

Cookie的签名即是使用一个存储在服务端的密钥对Cookie进行加密,Cookie中存储的数据是经过密钥加密的,因此客户端如果对Cookie进行修改,服务端校验就无法通过。

设置密钥

若需要给Cookie进行签名,首先需要给cookieParser的第一个参数传入一个字符串密钥:

// 解析Cookie
server.use(cookieParser(
  // 签名用密钥,需要保密,仅存储在服务端
  'NpLRTpy1vbBzEw2JcAxpf970kOk2RViDn5wKwrMv'
))

签名Cookie

这样就可以开始设置签名Cookie了,只需要在res.cookie方法的配置参数中设置signed: true属性:

res.cookie('password', 'test123', {
  httpOnly: true,
  domain: 'localhost',
  path: '/',
  maxAge: 14 * 86400000,
  // 开启该Cookie的签名模式
  signed: true
})

在浏览器打开http://localhost:8080/cookie,可以看到Cookie中被设置了password属性,其值为s%3Atest123.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg

如果用decodeURIComponent方法进行解码,结果为s:test123.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg

其意义如下:

  1. s表示该Cookie为签名Cookie
  2. test123表示该Cookie设置的值
  3. HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg表示对该值的签名,也就是说当服务端接收到该Cookie时,会使用服务端的密钥对test123进行签名,再与HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg进行对比,如果正确才可以使用。

此时可以看到服务端打印结果为signedCookies: {"password":"test123"}

在客户端修改签名的Cookie

如果用户在客户端对签名的Cookie进行了修改,例如在浏览器控制台,将password改为s%3Atest456.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg

此时在服务端打印的结果为signedCookies: {"password":false},表示校验失败。

同时浏览器中的Cookie值被重新修改为了s%3Atest123.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg

除非用户在修改签名的Cookie的值时,将该值的签名一起修改,否则校验是无法通过的。

但由于签名是由服务端的密钥计算而成,因此这个值通常是安全的。

不过,因为对Cookie进行签名,会占用更多的Cookie存储空间,而Cookie在浏览器中最多只能存储4K,所以签名不可滥用,只用来保护重要的数据即可。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant