Node实战篇:Express 中间件 cookie-parser(六)

图片

第一部分 cookie

首先了解一下会话

会话是一种持久的网络协议,用于完成服务器和客户端之间的一些交互行为。会话是一个比连接粒度更大的概念,一次会话可能包含多次连接,每次连接都被认为是会话的一次操作。

Cookie是由网景公司的前雇员Lou Montulli在1993年发明的,在RFC2109(已废弃,被RFC2965取代)里初次被描述的,每个客户端最多保持三百个cookie,每个域名下最多20个Cookie(实际上一般浏览器现在都比这个多,如Firefox是50个),而每个cookie的大小为最多4K,不过不同的浏览器都有各自的实现。对于cookie的使用,最重要的就是要控制cookie的大小,不要放入无用的信息,也不要放入过多信息。

1.1 cookie概述

图片


HTTP 是一个无状态协议,所以客户端每次发出请求时,下一次请求无法得知上一次请求所包含的状态数据;
Cookie是解决HTTP无状态性的有效手段,服务器可以设置或读取Cookie中所包含的信息。
简单的说,cookie是服务器发给用户的一个标识,用来帮助服务器识别用户,从而记录用户状态。

1. 用户第一次访问网站时,服务器向客户端发送 cookie。通常使用 HTTP 协议规定的 set-cookie 头操作。规范规定 cookie 的格式为 name = value 格式,且必须包含这部分。
2. 浏览器将 cookie 保存。
3. 每次请求浏览器都会将 cookie 发向服务器。

cookie 其他参数option:

1. path:表示 cookie 影响到的路径,匹配该路径才发送这个 cookie。
2. expires 和 maxAge:告诉浏览器这个 cookie 什么时候过期,expires 是 UTC 格式时间,maxAge 是 cookie 多久后过期的相对时间。当不设置这两个选项时,会产生 session cookie,session cookie 是 transient 的,当用户关闭浏览器时,就被清除。一般用来保存 session 的 session_id。
3. secure:当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效。
4. httpOnly:浏览器不允许脚本操作 document.cookie 去更改 cookie。一般情况下都应该设置这个为 true,这样可以避免被 xss ***拿到 cookie。
1.2 Cookie分类
1. 内存式Cookie: 存储在内存中,浏览器关闭后就会消失;
2. 硬盘式Cookie: 保存在硬盘中,其不会随浏览器的关闭而消失,除非用户手工清理或到了过期时间。
1.3 Cookie 的安全隐患

Cookie提供了一种手段使得HTTP请求可以附加当前状态, 现今的网站也是靠Cookie来标识用户的登录状态的:

  1. 用户提交用户名和密码的表单,这通常是一个POST HTTP请求。

  2. 服务器验证用户名与密码,如果合法则返回200(OK)并设置Set-Cookie为authed=true。

  3. 浏览器存储该Cookie。

  4. 浏览器发送请求时,设置Cookie字段为authed=true。

  5. 服务器收到第二次请求,从Cookie字段得知该用户已经登录。 按照已登录用户的权限来处理此次请求。



    这里面的问题在哪里?

假如我们直接设置Cookie字段为authed=true并发送该HTTP请求, 服务器岂不是被欺骗了?这种***非常容易,Cookie是可以被篡改的!

1.4 Cookie 防篡改机制

服务器可以为每个Cookie项生成签名,由于用户篡改Cookie后无法生成对应的签名, 服务器便可以得知用户对Cookie进行了篡改。

1. 在服务器中配置一个不为人知的字符串(我们叫它Secret),比如:x$sfz32。
2. 当服务器需要设置Cookie时(比如authed=false),不仅设置authed的值为false, 在值的后面进一步设置一个签名,最终设置的Cookie是authed=false|6hTiBl7lVpd1P。 3. 签名6hTiBl7lVpd1P是这样生成的:Hash('x$sfz32'+'true')。 要设置的值与Secret相加再取哈希。 4. 用户收到HTTP响应并发现头字段Set-Cookie: authed=false|6hTiBl7lVpd1P。
5. 用户在发送HTTP请求时,篡改了authed值,设置头字段Cookie: authed=true|???。 因为用户不知道Secret,无法生成签名,只能随便填一个。 6. 服务器收到HTTP请求,发现Cookie: authed=true|???。服务器开始进行校验: Hash('true'+'x$sfz32'),便会发现用户提供的签名不正确。

第二部分: cookie-parser

实例代码(不签名形式):

var express = require('express');
// 首先引入 cookie-parser 这个模块var cookieParser = require('cookie-parser');
var app = express(); app.listen(3000);
//不采用签名形式app.use(cookieParser());
// 如果请求中的 cookie 存在 bwf, 则输出 cookie// 否则,设置 cookie 字段 bwf, 并设置过期时间为1分钟
app.get('/', function (req, res) {  
//不采用签名形式获取cookie的方法:  req.cookies.  if (req.cookies.bwf) {    
   console.log(req.cookies);    res.send("再次欢迎访问");  } else {    
       //name value 过期时间       res.cookie('bwf', '1234', {maxAge: 6 * 1000, path: '/'});           res.send("欢迎第一次访问");  } });

chrome中cookie显示为name=value

图片


2.2 cookie-parser API

cookie-Parser和 express-session 这两个中间件在express 4版本之后解耦了,最开始如果用express-session 的话一定也要用cookieParser,

中间件包含三个模块:cookie cookie-praser cookie-signature.;
其中,cookie cookie-signature这两个模块是private的。所有的public API都在cookie-Parser中。
cookie-Parser 有四个接口;

module.exports = cookieParser;module.exports.JSONCookie = JSONCookie;module.exports.JSONCookies = JSONCookies;module.exports.signedCookie = signedCookie;module.exports.signedCookies = signedCookies;
req.secret:传入的秘钥用于对cookie进行加密req.cookies:对req.headers.cookie中的cookie进行解析,返回的一个对象req.signedCookies:保存的是解析后的cookie的真实值,但是可能还会被JSONCookie进行处理

2.2.1 cookieParser(secret, options) 返回的是一个中间件函数

1. secret(可选): 可以用string 或是 array 来签名cookie;默认无
2. options: 第一部分中cookie的可选对象;

2.2.2 cookieParser.JSONCookie(str)
将cookie作为json格式解析, 如果是json格式的value,就返回, 否则返回过去式;

2.2.3 cookieParser.JSONCookies(cookies)
给定一个对象,会重复调用cookieParser.JSONCookie

2.2.4 cookieParser.signedCookie(str, secret)
解析签名cookie,

2.2.5 cookieParser.signedCookies(cookies, secret)
给定一个对象, 重复调用cookieParser.signedCookie(str, secret)

实例代码(签名):

信息可见不可篡改

var express = require('express');
// 首先引入 cookie-parser 这个模块
var cookieParser = require('cookie-parser');var app = express();
/*--------------采用签名方式--------------*/

//第一步 设置签名 string
app.use(cookieParser('singedMyCookie')); app.get('/', function (req, res) {  
if (req.signedCookies.bwf) {
//第三步: 使用signedCookies获取cookie (采用签名形式获取cookie的方法:  req.signedCookies.    console.log(req.signedCookies);    res.send("再次欢迎访问");  } else {
   //第二步: 设置{signed: true}    res.cookie("bwf", "hhw", {signed: true});    res.send("欢迎第一次访问");  } }); app.listen(3000);

chrome中cookie显示为bwf=s%3......... 签名前是bwf=hhw

图片


猜你喜欢

转载自blog.51cto.com/15127576/2668219
今日推荐