03 网络面经:你真的了解Cookie和Session吗?
在初级面试中,关于Cookie和Session的区别是一个高频的面试题。如果只是机械的回答一下它们的区别,那你可能真的不了解Cookie和Session,就更别说灵活运用了。
这篇文章带你从Cookie和Session的初级应用到高级应用捋一遍,看看有多少不知道的内容。
什么是Cookie?
我们知道HTTP协议是无状态的,一次请求完成,不会持久化请求与相应的信息。那么,在购物车、用户登录状态、页面个性化设置等场景下,就无法识别特定用户的信息。这时Cookie就出现了。
Cookie是客户端保存用户信息的一种机制,将服务器发送到浏览器的数据保存在本地,下次向同一服务器再发起请求时被携带发送。对于Cookie,可以设置过期时间。
通常,Cookie用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。这样就解决了HTTP无状态的问题。
Cookie主要用于以下方面:
● 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
● 个性化设置(如用户自定义设置、主题等)
● 浏览器行为跟踪(如跟踪分析用户行为等)
Cookie存储在客户端,这就意味着,可以通过一些方式进行修改,欺骗服务器。针对这个问题,怎么解决呢?那就引入了Session。
什么是Session?
Session代表服务器和客户端一次会话的过程。
维基百科这样解释道:在计算机科学领域来说,尤其是在网络领域,会话(session)是一种持久网络协议,在用户(或用户代理)端和服务器端之间创建关联,从而起到交换数据包的作用机制,session在网络协议(例如telnet或FTP)中是非常重要的部分。
对照Cookie,Session是一种在服务器端保存数据的机制,用来跟踪用户状态的数据结构,可以保存在文件、数据库或者集群中。
当在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失,而会在整个用户会话中一直存在下去。当客户端关闭会话,或者Session超时失效时会话结束。
目前大多数的应用都是用Cookie实现Session跟踪的。第一次创建Session时,服务端会通过在HTTP协议中返回给客户端,在Cookie中记录SessionID,后续请求时传递SessionID给服务,以便后续每次请求时都可分辨你是谁。
Cookie与Session的区别
关于Cookie与Session的区别,就是在面试中经常回答的问题了。
● 作用范围不同,Cookie 保存在客户端(浏览器),Session 保存在服务器端。
存取方式的不同,Cookie只能保存 ASCII,Session可以存任意数据类型,比如UserId等。
● 有效期不同,Cookie可设置为长时间保持,比如默认登录功能功能,Session一般有效时间较短,客户端关闭或者Session超时都会失效。
● 隐私策略不同,Cookie存储在客户端,信息容易被窃取;Session存储在服务端,相对安全一些。
● 存储大小不同, 单个Cookie 保存的数据不能超过 4K,Session可存储数据远高于Cookie。
禁用Cookie会怎样?
如果客户在浏览器禁用了Cookie,该怎么办呢?
方案一:拼接SessionId参数。在GET或POST请求中拼接SessionID,GET请求通常通过URL后面拼接参数来实现,POST请求可以放在Body中。无论哪种形式都需要与服务器获取保持一致。
这种方案比较常见,比如老外的网站,经常会提示是否开启Cookie。如果未点同意或授权,会发现浏览器的URL路径中往往有"?sessionId=123abc"这样的参数。
方案二:基于Token(令牌)。在APP应用中经常会用到Token来与服务器进行交互。Token本质上就是一个唯一的字符串,登录成功后由服务器返回,标识客户的临时授权,客户端对其进行存储,在后续请求时,通常会将其放在HTTP的Header中传递给服务器,用于服务器验证请求用户的身份。
分布式系统中Session如何处理?
在分布式系统中,往往会有多台服务器来处理同一业务。如果用户在A服务器登录,Session位于A服务器,那么当下次请求被分配到B服务器,将会出现登录失效的问题。
针对类似的场景,有三种解决方案:
方案一:请求精确定位。也就是通过负载均衡器让来自同一IP的用户请求始终分配到同一服务上。比如,Nginx的ip_hash策略,就可以做到。
方案二:Session复制共享。该方案的目标就是确保所有的服务器的Session是一致的。像Tomcat等多数主流web服务器都采用了Session复制实现Session的共享.
方案三:基于共享缓存。该方案是通过将Session放在一个公共地方,各个服务器使用时去取即可。比如,存放在Redis、Memcached等缓存中间件中。
在Spring Boot项目中,如果集成了Redis,Session共享可以非常方便的实现。
同源策略与跨域请求
所谓的“同源”指的是“三个相同”:协议相同、域名相同、端口相同。只有这三个完全相同,才算是同源。
同源策略的目的:是为了保证用户信息的安全,防止恶意的网站窃取数据。
比如,用户访问了银行网站A,再去浏览其他网站,如果其他网站可以读取A的Cookie,隐私信息便会泄露。更可怕的是,通常Cookie还用来保存用户登录状态,会出现冒充用户行为。因此,"同源策略"是必需的,如果Cookie可以共享,互联网就毫无安全可言了。
同源策略保证了一定的安全性,但在某些场景下也带来了不便,比如常见的跨域请求问题。
在HTML中,<a>,<form>, <img>, <script>, <iframe>, <link> 等标签以及Ajax都可以指向一个资源地址,而所谓的跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。同源即同域,三项有一项不同便会出现跨域请求。
浏览器会对跨域请求做出限制,因为跨域请求可能会被利用发动CSRF攻击。
CSRF(Cross-site request forgery),即“跨站请求伪造”,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。CSRF攻击者在用户已经登录目标网站之后,诱使用户访问一个攻击页面,利用目标网站对用户的信任,以用户身份在攻击页面对目标网站发起伪造用户操作的请求,达到攻击目的。
针对跨域请求通常有如下方法:
● 通过代理避开跨域请求;
● 通过Jsonp跨域;
● 通过跨域资源共享(CORS);
关于跨域的具体解决步骤,就不再展开了。
小结
在准备面试题时,我们通常只会去背诵Cookie和Session的区别。但只有系统的学习才能更深刻的把知识点串联起来,形成强大记忆,融会贯通的效果。比如,本文了解了Cookie与Session出现的原因、解决的问题以及引入之后又会带来什么问题等,更加系统全面的掌握了这一知识点。
文章转载自公众号:程序员新视界