本篇文章主要总结了 cookie session的原理,以及会话控制。下面是使用简单的代码来解析,还是比较容易懂的,还可能存在不足,欢迎各位大佬☞正
想要了解cookie,首先需要了解http是什么。好了,下面就从http的原理开始说吧
HTTP的诞生:
CERN(欧洲核子研究组织)的蒂姆 • 伯纳斯 - 李(Tim BernersLee) 博士提出了一种能让远隔两地的研究者们共享知识的设想。
最初设想的基本理念是:借助多文档之间相互关联形成的超文本 (HyperText),连成可相互参阅的 WWW(World Wide Web,万维 网)。
现在已提出了 3 项 WWW 构建技术,分别是:把 SGML(Standard Generalized Markup Language,标准通用标记语言)作为页面的文本标 记语言的 HTML(HyperText Markup Language,超文本标记语言); 作为文档传递协议的 HTTP ;指定文档所在地址的 URL(UniformResource Locator,统一资源定位符)。
如果你想要更深入了解http,那么需要了解他的底层Tcp,可以参考电子书图解HTTP
HTTP 是不保存状态的协议
HTTP 是一种不保存状态,即无状态(stateless)协议。HTTP 协议自 身不对请求和响应之间的通信状态进行保存。也就是说在 HTTP 这个 级别,协议对于发送过的请求或响应都不做持久化处理。
那么这个无状态中的“状态”,是什么呢:可以简单这样理解:就是信息,这些信息是由服务端所维护的与客户端交互的信息(也称为状态信息),因为HTTP本身是不保存任何用户的状态信息的,所以HTTP是无状态的协议。
cookie的诞生:
HTTP 协议自身不具备保存之前发送过的请求或响应的功能 ,也就是Http本身是无状态的,使用 HTTP 协议,每当有新的请求发送时,就会有对应的新响应产生。协议本身并不保留之前一切的请求或响应报文的信息。这是为了 更快地处理大量事务,确保协议的可伸缩性,自然可减少服务器的 CPU 及内存资源的消耗。(简单来说,浏览一写静态的文件和文档,已经足够使用了)
图示:服务器管理全部客户端状态则会成为负担
这时候我们考虑一个问题,假设要求登录认证的 Web 页面本身无法进行状态的管理(不记录已 登录的状态),那么每次跳转新页面不是要再次登录,就是要在每次 请求报文中附加参数来管理登录状态。
这个时候。很多业务网站都需要状态信息得以保存;但是,一方面是http本身不会去改变它的这种无状态的特性,所以这个时候需要引入一些机制来装饰下HTTP,让HTTP达到可以保存客户端和服务端之间通信的状态。
cookie和session的引入:
通过引入cookie和session体系机制来维护状态信息,Cookie 技术通过在请求和响应报文中写入 Cookie 信 息来控制客户端的状态。Cookie 会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie 的 首部字段信息,通知客户端保存 Cookie。当下次客户端再往该服务器 发送请求时,客户端会自动在HTTP请求报文中加入 Cookie 值后发送出 去。cookie中存有sessionId这样的信息(session是基于cookie的),来到服务器这边对比服务器上的记录。最后得到之前 的状态信息。
Cookie技术原理:
Cookie 的工作机制是用户识别及状态管理,Cookie 技术通过在请求和响应报文中写入 Cookie 信 息来控制客户端的状态。由服务器发送给客户端(浏览器)的小量信息,以{key:value}的形式存在。Cookie 会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie 的 首部字段信息,通知客户端保存 Cookie。当下次客户端再往该服务器 发送请求时,客户端会自动在HTTP请求报文中加入 Cookie 值后发送出 去,来到服务器这边对比服务器上的记录。最后得到之前 的状态信息。
Cookie的属性:
Cookie 服务的首部字段
1. Set-Cookie字段的属性
expires 属性
Cookie 的 expires 属性指定浏览器可发送 Cookie 的有效期。 当省略 expires 属性时,其有效期仅限于维持浏览器会话(Session) 时间段内。这通常限于浏览器应用程序被关闭之前。
path 属性
Cookie 的 path 属性可用于限制指定 Cookie 的发送范围的文件目录。 不过另有办法可避开这项限制,看来对其作为安全机制的效果不能抱 有期待。
domain 属性
通过 Cookie 的 domain 属性指定的域名可做到与结尾匹配一致。比 如,当指定 example.com 后,除 example.com 以外,www.example.com 或 www2.example.com 等都可以发送 Cookie。
secure 属性
Cookie 的 secure 属性用于限制 Web 页面仅在 HTTPS 安全连接时,才 可以发送 Cookie。发送 Cookie 时,指定 secure 属性的方法如下所示。
Set-Cookie: name=value; secur
HttpOnly 属性
Cookie 的 HttpOnly 属性是 Cookie 的扩展功能,它使 JavaScript 脚本 无法获得 Cookie。其主要目的为防止跨站脚本攻击(Cross-site scripting,XSS)对 Cookie 的信息窃取。
HttpOnly=true
通过上述设置,通常从 Web 页面内还可以对 Cookie 进行读取操作。但使用 JavaScript 的 document.cookie 就无法读取附加 HttpOnly 属性后 的 Cookie 的内容了。因此,也就无法在 XSS 中利用 JavaScript 劫持 Cookie 了。
2.Cookie
Cookie: status=enable
首部字段 Cookie 会告知服务器,当客户端想获得 HTTP 状态管理支 持时,就会在请求中包含从服务器接收到的 Cookie。接收到多个 Cookie 时,同样可以以多个 Cookie 形式发送。
Cookie小案例:记录访问浏览器的数次
此时httponly也不太安全,它可以手动操作改动,所以下面可以加入签名来实现加密。
就比如jd.com里面的cookie类似,你根本看不懂是一串看不懂的数字,但是你不知道它代表什么含义?
浏览器可以修改cookie -----> 签名
此时改变cookie的值,已经毫无意义了,改变之后,发送到服务器对比之后,发现状态不一样,会重新请求。
const http = require("http");
const querystring = require("querystring");
const sign = (value) => {
return require("crypto").createHmac("sha256", "abc").update(value).digest("base64").replace(/\+/g, "")
}
http.createServer((req, res) => {
let arr = [];
res.setCookie = function (key, value, options = {}) {
let opts = [];
if (options.domain) {
opts.push(`domain=${options.domain}`)
}
if (options.maxAge) {
opts.push(`max-age=${options.maxAge}`)
}
if (options.httpOnly) {
opts.push(`httpOnly=${options.httpOnly}`)
}
if (options.signed) {
value = value + '.' + sign(value)
}
arr.push(`${key}=${value}; ${opts.join("; ")}`)
res.setHeader('Set-Cookie', arr);
}
req.getCookie = function (key,options = {}) {
let obj = querystring.parse(req.headers.cookie, "; ");
if (options.signed) {
if (obj[key]) {
let [value, s] = obj[key].split('.')
console.log(value)
let newSign = sign(value);
// console.log(s,newSign)
if (s === newSign) {
return value
} else {
return undefined;
}
}
}
return obj[key];
}
if (req.url === "/write") {
// res.setCookie("name","wangcai");
// res.setCookie("age","100");
res.end("write ok ~")
return
}
if (req.url === "/read") {
res.end(req.getCookie("age") || 'empty');
}
if (req.url === "/visit") {
res.setHeader("Content-type", "text/plain; charset=utf8")
let visit = req.getCookie("visit",{signed:true});
if (visit) {
visit = visit - 0 + 1;
res.setCookie("visit", visit + "", { httpOnly: true ,signed:true})
} else {
visit = 1;
res.setCookie("visit", "1", { httpOnly: true ,signed:true})
}
res.end(`当前第${visit}次访问`)
}
}).listen(3000);
Session技术:
Cookie机制弥补了HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。
与Cookie不同的是,session是以服务端保存状态的。
Session技术原理:
session是基于cookie 第1次请求时,服务器会把一个session_id以cookie形式种植给浏览器。以后客户端在访问服务端时候,http会带着session_id,服务器会先检查这个客户端的请求里是否已包含了一个session标识----sessionId。如果已包含这个sessionId,则说明以前已经为此客户端创建过session,服务器就按照sessionId把这个session检索出来使用。
session小案例:
将session类比与一张饭卡,起初500元,每次刷新减少100
const http = require("http");
const querystring = require("querystring");
let uuid = require("uuid")
let cardName = "tian"
// 先把session存储到内存中 后面我们会把session数据存储到数据库
let session = {};
http.createServer((req,res)=>{
let arr = [];
res.setCookie = function(key,value,options={}){
let opts = [];
if(options.domain){
opts.push(`domain=${options.domain}`)
}
if(options.maxAge){
opts.push(`max-age=${options.maxAge}`)
}
if(options.httpOnly){
opts.push(`httpOnly=${options.httpOnly}`)
}
arr.push(`${key}=${value}; ${opts.join("; ")}`)
res.setHeader('Set-Cookie', arr);
}
req.getCookie = function(key,options = {}){
let obj = querystring.parse(req.headers.cookie,"; ");
return obj[key];
}
if(req.url === "/eat"){
let id = req.getCookie(cardName);
if(id){ // 有卡
// session[id].mny = session[id].mny - 100
session[id].mny -= 100
res.end("current money is $"+session[id].mny)
}else{
let cartId = uuid.v4();
// console.log(cartId) // c1cddd32-e6f7-40fa-9fed-b711489a4bf9
session[cartId] = {mny:500}
res.setCookie(cardName,cartId)
res.end("current money is $500")
}
res.end("eat...")
}
}).listen(3000);
一个常见且重要的面试题:
localStorage, sessionStorage, cookie, session有什么区别?
localStorage 不能跨域存取 最大存5M 超过5M的数据就会丢失 在发送请求时,不会带上 存储数据永久存储
sessionStorage 当浏览器关闭时,里面的数据就丢失
cookie 服务器种植的,每次请求都会带上cookie,安全,解决无状态问题,最多4K,浪费流量
session 基于cookie 保存在服务器(内存,入库) 相对安全