文章导读

cookie-parser是Express的中间件,用来实现cookie的解析,是官方脚手架内置的中间件之一。

它的使用非常简单,但在使用过程中偶尔也会遇到问题。一般都是因为对Express + cookie-parser的签名、验证机制不了解导致的。

本文深入讲解Express + cookie-parser的签名和验证的实现机制,以及cookie签名是如何增强网站的安全性的。

文本同步收录于GitHub主题系列《Nodejs学习笔记》

入门例子:cookie设置与解析

先从最简单的例子来看下cookie-parser的使用,这里采用默认配置。

  1. cookie设置:使用Express的内置方法res.cookie()
  2. cookie解析:使用cookie-parser中间件。
var express = require('express');
var cookieParser = require('cookie-parser');
var app = express();app.use(cookieParser());app.use(function (req, res, next) {console.log(req.cookies.nick); // 第二次访问,输出chyingpnext();
});app.use(function (req, res, next) {  res.cookie('nick', 'chyingp');res.end('ok');
});app.listen(3000);
复制代码

在当前场景下,cookie-parser中间件大致实现如下:

app.use(function (req, res, next) {req.cookies = cookie.parse(req.headers.cookie);next();
});
复制代码

进阶例子:cookie签名与解析

出于安全的考虑,我们通常需要对cookie进行签名。

例子改写如下,有几个注意点:

  1. cookieParser初始化时,传入secret作为签名的秘钥。
  2. 设置cookie时,将signed设置为true,表示对即将设置的cookie进行签名。
  3. 获取cookie时,可以通过req.cookies,也可以通过req.signedCookies获取。
var express = require('express');
var cookieParser = require('cookie-parser');
var app = express();// 初始化中间件,传入的第一个参数为singed secret
app.use(cookieParser('secret'));app.use(function (req, res, next) {console.log(req.cookies.nick); // chyingpconsole.log(req.signedCookies.nick); // chyingpnext();
});app.use(function (req, res, next) {  // 传入第三个参数 {signed: true},表示要对cookie进行摘要计算res.cookie('nick', 'chyingp', {signed: true});res.end('ok');
});app.listen(3000);
复制代码

签名前的cookie值为chyingp,签名后的cookie值为s%3Achyingp.uVofnk6k%2B9mHQpdPlQeOfjM8B5oa6mppny9d%2BmG9rD0,decode后为s:chyingp.uVofnk6k+9mHQpdPlQeOfjM8B5oa6mppny9d+mG9rD0

下面就来分析下,cookie的签名、解析是如何实现的。

cookie签名、验证实现剖析

Express完成cookie值的签名,cookie-parser实现签名cookie的解析。两者共用同一个秘钥。

cookie签名

Express对cookie的设置(包括签名),都是通过res.cookie()这个方法实现的。

精简后的代码如下:

res.cookie = function (name, value, options) {  var secret = this.req.secret;var signed = opts.signed;// 如果 options.signed 为true,则对cookie进行签名if (signed) {val = 's:' + sign(val, secret);}this.append('Set-Cookie', cookie.serialize(name, String(val), opts));return this;
};
复制代码

sign为签名函数。伪代码如下,其实就是把cookie的原始值,跟hmac后的值拼接起来。

敲黑板划重点:签名后的cookie值,包含了原始值。

function sign (val, secret) {return val + '.' + hmac(val, secret);
}
复制代码

这里的secret哪来的呢?是cookie-parser初始化的时候传入的。如下伪代码所示:

var cookieParser = function (secret) {return function (req, res, next) {req.secret = secret;// ...next();};
};app.use(cookieParser('secret'));
复制代码

签名cookie解析

知道了cookie签名的机制后,如何"解析"签名cookie就很清楚了。这个阶段,中间件主要做了两件事:

  1. 将签名cookie对应的原始值提取出来
  2. 验证签名cookie是否合法

实现代码如下:

// str:签名后的cookie,比如 "s:chyingp.uVofnk6k+9mHQpdPlQeOfjM8B5oa6mppny9d+mG9rD0"
// secret:秘钥,比如 "secret"
function signedCookie(str, secret) {// 检查是否 s: 开头,确保只对签过名的cookie进行解析if (str.substr(0, 2) !== 's:') {return str;}// 校验签名的值是否合法,如合法,返回true,否则,返回falsevar val = unsign(str.slice(2), secret);if (val !== false) {return val;}return false;
}
复制代码

判断、提取cookie原始值比较简单。只是是unsign方法名比较有迷惑性。

一般只会对签名进行合法校验,并没有所谓的反签名。

unsign方法的代码如下:

  1. 首先,从传入的cookie值中,分别提取出原始值A1、签名值B1。
  2. 其次,用同样的秘钥对A1进行签名,得到A2。
  3. 最后,根据A2、B1是否相等,判断签名是否合法。
exports.unsign = function(val, secret){var str = val.slice(0, val.lastIndexOf('.')), mac = exports.sign(str, secret);return sha1(mac) == sha1(val) ? str : false;
};
复制代码

cookie签名的作用

主要是出于安全考虑,防止cookie被篡改,增强安全性。

举个小例子来看下cookie签名是如何实现防篡改的。

基于前面的例子展开。假设网站通过nick这个cookie来区分当前登录的用户是谁。在前面例子中,登录用户的cookie中,nick对应的值如下:(decode后的)

s:chyingp.uVofnk6k+9mHQpdPlQeOfjM8B5oa6mppny9d+mG9rD0
复制代码

此时,有人试图修改这个cookie值,来达到伪造身份的目的。比如修改成xiaoming

s:xiaoming.uVofnk6k+9mHQpdPlQeOfjM8B5oa6mppny9d+mG9rD0
复制代码

当网站收到请求,对签名cookie进行解析,发现签名验证不通过。由此可判断,cookie是伪造的。

hmac("xiaoming", "secret") !== "uVofnk6k+9mHQpdPlQeOfjM8B5oa6mppny9d+mG9rD0"
复制代码

签名就一定能够确保安全吗

当然不是。

上个小节的例子,仅通过nick这个cookie的值来判断登录的是哪个用户,这是一个非常糟糕的设计。虽然在秘钥未知的情况下,很难伪造签名cookie。但用户名相同的情况下,签名也是相同的。这种情况下,其实是很容易伪造的。

另外,开源组件的算法是公开的,因此秘钥的安全性就成了关键,要确保秘钥不泄露。

还有很多,这里不展开。

小结

本文主要对Express + cookie-parser的签名和解析机制进行相对深入的介绍。

不少类似的总结文章中,把cookie的签名说成了加密,这是一个常见的错误,读者朋友需要注意一下。

签名部分的介绍,稍微涉及一些简单的安全知识,对这块不熟悉的同学可以留言交流。为讲解方便,部分段落、用词可能不够严谨。如有错漏,敬请指出。

相关链接

https://github.com/expressjs/cookie-parser

https://github.com/chyingp/nodejs-learning-guide

Express使用进阶:cookie-parser中间件实现深入剖析相关推荐

  1. 渲染静态页面、get请求、post请求、express框架、路由、中间件

    1. 渲染静态页面 const http = require('http'); const fs = require('fs'); const url = require('url'); const ...

  2. http协议、模块、express框架以及路由器、中间件和mysql模块

    一.http协议 是浏览器和web服务器之间的通信协议 1.通用头信息 request url:请求的url,向服务器请求的数据 request method:请求的方式   get.post sta ...

  3. express 框架之 路由与中间件

    1.  什么是router路径,什么是middleware? 我们输入www.baidu.com 来访问百度的主页,浏览器会自动转换为 http://www.baidu.com:80/(省略一些参数) ...

  4. Express文件表单解析中间件 Multer简介

    前言 Express中最常使用的form解析中间件就是body-parser了,但是它明确表示不会支持multipart/form-data类型的表单. 所以在body-parser官方文档中提供了如 ...

  5. Python爬虫中urllib库的使用进阶--cookie的使用

    什么是cookie: 在网站中,http请求是无状态的.也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户.cookie的出现就是为了解决这个问题,第一次登 ...

  6. .net core 中间件管道底层剖析

    .net core 管道(Pipeline)是什么? 由上图可以看出,.net core 管道是请求抵达服务器到响应结果返回的中间的一系列的处理过程,如果我们简化一下成下图来看的话,.net core ...

  7. flink checkpoint 重启_Flink进阶教程:Checkpoint机制原理剖析与参数配置

    在Flink状态管理详解:Keyed State和Operator List State深度解析这篇文章中,我们介绍了Flink的状态都是基于本地的,而Flink又是一个部署在多节点的分布式引擎,分布 ...

  8. Express框架之express-session的插件的攻坚战

    第一步:我们看看req对象在Express中被封装了那些内容(简易版): httpVersionMajor: 1,httpVersionMinor: 1,httpVersion: '1.1',comp ...

  9. Express全系列教程之(五):Express的中间件

    一.中间件 从字面意思,我们可以了解到它大概就是做中间代理操作,事实也是如此:大多数情况下,中间件就是在做接收到请求和发送响应中间的一系列操作.事实上,express是一个路由和中间件的web框架,E ...

最新文章

  1. 三年开发剑指阿里,复习耗时168天,三面阿里巴巴,成功定级P7
  2. win7怎么去除快捷方式的小箭头
  3. 萤石云平台接入_前端接入监控视频
  4. 10个实用的机器学习建议
  5. 《软件调试》读书笔记:第13章 硬错误和蓝屏
  6. python的图像傅里叶变换 np.fft.fft2 cv.dft 函数
  7. 游戏开发学什么?四步修炼骨灰级高手
  8. 电音插件auto_自动电音基调查询软件助手完美支持32_64bit系统所有电音插件
  9. 节约中小企业运维成本方案
  10. linux ps命令是什么,linux中的ps命令的详细解释
  11. 企业微信周末加班怎么打卡?
  12. 数据库的ACID(原子性、一致性、隔离性与持久性)
  13. CWnd与HWND的区别与联系(相互转换)完全解析
  14. java web聊天室论文_基于javaweb聊天室.doc
  15. BP客户主数据信用数据批量修改
  16. jquery怎么根据id获取元素值
  17. 【蓝桥杯】python进制转换16进制转8进制。16进制转10进制。10进制转16进制。
  18. jsf<h:outpytText>实现换行
  19. 国科大学习资料--最优化计算方法(王晓)--期末考试试卷3
  20. css 毛玻璃_我写CSS的常用套路(附demo的效果实现与源码)

热门文章

  1. Python[8] :paramiko模块多进程批量管理主机
  2. 1.1 创建 Android 项目
  3. http://www.ibm.com/developerworks/cn/java/j-lo-hotswapcls/
  4. popoverController简单介绍
  5. 如何区别***工具与病毒
  6. 基于mini2440的两种触屏中断程序(T35)
  7. Ubuntu 10.04正式发布
  8. 解读百度AutoDL:打破SOTA纪录的神经架构搜索是如何炼成的
  9. Money-去哪了每日站立会议
  10. 查看数据库中存在触发器的表