Luckylau's Blog

深入理解http协议(2)

本章主要介绍Cookie与Session以及JWT,同时讨论如何安全进行会话跟踪。

什么是Cookie

​ Http协议是无状态的,为了解决Http协议无法维持状态的问题,1994年网景通讯的一名员工 Lou Montulli将 “magic cookies” 的概念应用到 Web 通讯中。他试图解决 Web 的第一个购物车应用,现在购物车成了购物网站的支柱。他的原始说明文档提供了 cookie 工作原理的基本信息,该文档后来被作为规范纳入到 RFC 2109(大多数浏览器的实现参考文档)中,最终被纳入到 RFC 2965 中。Montulli 也被授予 cookie 的美国专利。网景浏览器在它的第一个版本中就开始支持 cookie,现在所有 Web 浏览器都支持 cookie。

​ Java中把Cookie封装成了javax.servlet.http.Cookie类。每个Cookie都是该Cookie类的对象。服务器通过操作Cookie类对象对客户端Cookie进行操作。通过request.getCookie()获取客户端提交的所有Cookie(以Cookie[]数组形式返回),通过response.addCookie(Cookie cookie)向客户端设置Cookie。

Cookie的属性

1
2
3
4
5
6
7
8
String name:该Cookie的名称。Cookie一旦创建,名称便不可更改。
Object value:该Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码。
int maxAge:该Cookie失效的时间,单位秒。如果为正数,则该Cookie在>maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1。
boolean secure:该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。
String path:该Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”。
String domain:可以访问该Cookie的域名。如果设置为“.google.com”,则以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”。
String comment:该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明。 int version:该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范.
boolean httponly: 若此属性为true,则只有在http请求头中会带有此cookie的信息,而不能通过document.cookie来访问此cookie

Cookie的优缺点

cookie只能保存字符串类型,以文本的方式;

单个cookie保存的数据不能超过4kb;

有些状态不可能保存在客户端;

cookie数据有路径(path)的概念,可以限制cookie只属于某个路径下;

什么是Session

为什么有了cookie之后还会有session使用呢?在解决这个疑问,首先要清楚session。Session本身是记录客户状态的机制,决定客户端与服务端交互是继续还是中断,session常被翻译为“会话”,但这是一个抽象的概念,它的基本原理是它将信息保存在服务端,客户端通过一定方式传递sessionid(例如借助cookie)来保持与服务端的连接。session在设计来说比cookie更更安全:sessionID存储在cookie中,若要攻破session首先要攻破cookie;sessionID是要有人登录,或者启动session_start才会有,所以攻破cookie也不一定能得到sessionID;第二次启动session_start后,前一次的sessionID就是失效了,session过期后,sessionID也随之失效;sessionID是加密的;

Session优缺点

session通过类似与Hashtable的数据结构来保存,能支持任何类型的对象(session中可含有多个对象。

session大小没有限制;

Session保存的东西越多,就越占用服务器内存,对于用户在线人数较多的网站,服务器的内存压力会比较大;

什么是JWT

​ Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JWT的结构

​ 它是由三部分组成:header,payload,signature。header中通常来说由token的生成算法和类型组成;payload中则用来保存相关的状态信息;signature部分由header,payload,secret_key三部分生成。

​ 首先用户发出登录请求,服务端根据用户的登录请求进行匹配,如果匹配成功,将相关的信息放入payload中,利用上述算法,加上服务端的密钥生成token,这里需要注意的是secret_key很重要,如果这个泄露的话,客户端就可以随意篡改发送的额外信息,它是信息完整性的保证。生成token后服务端将其返回给客户端,客户端可以在下次请求时,将token一起交给服务端,一般来说我们可以将其放在Authorization首部中,这样也就可以避免跨域问题。接下来,服务端根据token进行信息解析,再根据用户信息作出相应的操作。

Cookie、Session和JWT区别与联系

​ cookie的信息是存在客户端浏览器的,不需要维护状态,但是使用cookies时,在多个域名下,会存在跨域问题,同时一般浏览器对cookie数量和大小都有限制;session的信息存在服务端,需要维护状态,当高并发时候会影响服务器的性能, 当有多台机器时,如何共享session也会是一个问题。一般Session机制实现会借助与Cookie传递SessionId。JWT采用token机制,解决http无状态问题的,目前也并不会完全替代Cookie、Session机制。因为它自身也存在一些问题,比如登录状态信息续签问题,比如设置token的有效期为一个小时,那么一个小时后,如果用户仍然在这个web应用上,这个时候当然不能指望用户再登录一次。目前可用的解决办法是在每次用户发出请求都返回一个新的token,前端再用这个新的token来替代旧的,这样每一次请求都会刷新token的有效期。但是这样,需要频繁的生成token;用户主动注销。JWT并不支持用户主动退出登录,当然,可以在客户端删除这个token,但在别处使用的token仍然可以正常访问。所以JWT天然的适合在一定时间内操作,否则链接失效的场景,比如邮箱注册验证链接等。

使用场景

Cookie的应用

​ 判断用户是否登陆过网站,以便下次登录时能够实现自动登录(或者记住密码)。如果我们删除cookie,则每次登录必须从新填写登录的相关信息;保存上次登录的时间等信息;保存上次查看的页面;浏览计数;

Session的应用

​ 虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为Session需要使用Cookie作为识别标志。HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。该Cookie为服务器自动生成的,它的maxAge属性一般为–1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。

​ 同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。但是由浏览器窗口内的链接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的Cookie,因此会共享一个Session。注意:新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。例如,在链接上右击,在弹出的快捷菜单中选择“在新窗口中打开”时,子窗口便可以访问父窗口的Session。

Session+URL地址重写

URL地址重写是对客户端不支持Cookie的解决方案。URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。HttpServletResponse类提供了encodeURL(Stringurl)实现URL地址重写。

Session+隐藏的表单域

隐藏的表单域是一种最简单的方式,将字段隐藏在HTML表单中,但不在客户端显示。比如在第一张页面中输入用户名和密码登陆,服务器生成响应返回第二张页面。当第二张页面提交时可能仍然需要知道来自第一张页面中的用户名。那么就可以通过隐藏表单域来实现这一连续的过程。当第一张页面提交后,服务器端作出响应返回第二张页面,此页面中用隐藏域记录了来自登陆时的用户名。通俗说就是当服务器回发给客户端的响应中,就同时把用户名再次回发到客户端,用隐藏域隐藏起来,是不可见的。当第二张页面提交时,此隐藏域中的用户名一并随表单提交。这样服务器就仍然可以判断此用户是否与以前的用户相同。于是,再次处理完结果后继续将响应回发给客户端,且此响应中也仍然包含了用户名,在客户端中仍然用隐藏域将这一信息隐藏。这样就完成了一个连续请求的动作,但是对于用户,这是不可见的。

JWT的应用

用于设计用户认证和授权系统,甚至实现Web应用的单点登录,多web服务器下实现无状态分布式身份验证等。

参考

https://www.cnblogs.com/andy-zhou/p/5360107.html

https://www.zhihu.com/question/19786827

https://blog.csdn.net/yunnysunny/article/details/26935637

https://blog.csdn.net/webwalker/article/details/707927

https://www.cnblogs.com/henryhappier/archive/2011/03/03/1969564.html

https://blog.csdn.net/qq_29831979/article/details/75374751

https://www.jianshu.com/p/ecd455e1c7cd

https://www.cnblogs.com/cencenyue/p/7604651.html

https://blog.csdn.net/u011145904/article/details/77745777

https://www.jianshu.com/p/fcc1a6482143?from=timeline

Luckylau wechat
如果对您有价值,看官可以打赏的!