Learning Card
- http是无状态的
- cookie和session来储存用户信息
- cookie相当于session的暗号
- 操作方法
- 原生:
res.setHeader('Set-Cookie', [key=value])
cookie-parser
中间件- 读取:
req.cookies
- 写入:
res.cookie(key, value, {attributes})
- 签名:
req.secret
- 解析签名:
server.use(cookieParser(secret))
- 防止修改:
httpOnly: true
- 清除:
res.clearCookie(key)
- 读取:
- 原生:
HTTP协议的一大特点是无状态。所谓无状态就是对于之前处理的事务没有记忆能力,我们可以理解为刚刚才登录了这个网站,一不小心关闭页面之后再打开,之前在页面上的操作就没有留下任何痕迹了,不会有现在的7天之内免登录之类的便捷操作。
这样看起来比较安全,但是会导致之后每一次使用网页都要重传之前所有的数据,非常不方便,所以就有了两个专门用来解决这一问题的技术,就是Cookie和Session。
Cookie和Session
Cookie是保存在浏览器上的数据,它用来辨识用户身份。Session则是保存在服务器上的数据,它保存了用户的信息数据。
但我们知道,保存在浏览器上的数据都是不安全的,因为用户可以自行修改上面的数据。我们随意打开一个网站,比如百度,打开开发者工具中的Applciation,查看Cookies:
可以看到列表里有很多数据。这里我们选择BD_HOME
,并在控制台修改它的值:
此时我们再查看Application,就会发现BD_HOME
的value
已经变成了200:
那么既然cookie这么不安全,我们为什么还使用它呢?
原理
事实上,cookie和session是搭配使用的。
浏览器第一次访问网站的时候,cookie是空的,这时网站服务器会生成一个session_id给cookie,同时对应session_id存储这个用户的信息,下次浏览器再访问网站的时候,cookie中就携带了这个session_id,服务器根据session_id来查找用户的信息。可以说cookie就像一个暗号一样,服务器依赖cookie来查找session中的数据。
那我们在后台如何对cookie进行读写呢?
操作
1. 原生方法setHeader('Set-Cookie')
原生node.js通过在响应请求的头信息里设置Set-Cookie
来写入cookie信息。我们先在本地服务器查看cookie:
接下来我们来添加自定义的cookie
1 | const http = require("http"); |
此时我们再查看cookie,就比之前多了两条设置的内容:
2. cookie-parser
读取和设置cookie
原生的请求对象req
没有req.cookies
属性,所以我们无法直接获取cookie,需要用到一个中间件cookie-parser
1 | const express = require("express"); |
控制台输出:
Application的cookie列表:
在http://localhost:9000/aaa
页面的Application中:
可以看到原生node.js和express框架设置cookie的方法略有不同
3. cookie签名
浏览器中的cookie虽然只是用来开启session,但是如果被别人盗取了cookie,同样能以你的身份来获取session数据,因此我们需要对cookie做一些保险处理。其中一个方法是给cookie签名。
1 | const express = require("express"); |
cookieParser中间件可以接受一个字符串作为加密的钥匙,在res.cookie
设置cookie值时,加上{signed: true}
就会给cookie加密。输出结果:
列表中的cookie则变成了一长串字符串:
但是可以看到,加密后的cookie还是可以轻易分辨出设置的值。实际上,签名无法保证原内容不被看见,只能杜绝修改。
服务器根据秘钥对cookie签名,如果利用同一个秘钥解析出来的cookie和原cookie一样则表明cookie没有被修改过。
在代码中有两个地方都出现了我们设置的签名字符串abcdefg
,这两个的作用是不同的。
res.secret
用于给cookie签名,而cookieParser()
中的字符串用于输出原cookie内容(unsign),如果我们将cookieParser()
中的字符串去掉,输出结果就是签名过的cookie:
cookie的httpOnly
属性
签名过的cookie还是可以被修改的:
想要cookie无法再浏览器中被修改,可以在服务器端设置cookie的httpOnly
属性:
1 | const express = require("express"); |
我们再尝试在浏览器端修改:
控制台并没有报错,但是修改没有生效:
而且httpOnly
为true
的cookie无法在浏览器获取:
4. 清除cookie内容 clearCookie
1 | const express = require("express"); |
res.clearCookie(key)
用于删除对应的cookie值:
res.clearCookie()
不会删除所有cookie,如果括号内没有值,则不会删除任何cookie。