Session
Session 对应的类为 javax.servlet.http.HttpSession 类。每个来访者对应一个 Session 对象,所有该客户的状态信息都保存在这个 Session 对象里。Session 对象是在客户端第一次请求服务器的时候创建的。Session 也是一种 key-value 的属性对,通过 getAttribute(String key)
和 setAttribute(String key,Object value)
方法读写客户状态信息。Servlet 里通过 request.getSession()
方法获取该客户的 Session。
Session 的使用比 Cookie 方便(例如直接保存某个对象,而 Cookie 则是基于字符串来操作),但是过多的Session 存储在服务内存中,会对服务器造成压力。
Session 与 Cookie 的联系:HTTP 协议是无状态的,Session 不能依据 HTTP 连接来判断是否为同一客户。在一般情况下,服务器对用户的判断是依赖于 Cookie 中被存入的值 SESSIONID (服务端在创建Session的时候产生)的。有时候为了安全性,我们会不使用预存 SESSIONID 的方法,转而使用URL重写技术。
Session 超时时间
随着越来越多的用户访问服务器,Session 也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的 Session 从内存删除,这个时间就是 Session 的超时时间。也就是说, Session 超时的概念是客户端两次请求的最大间隔时长。在 Tomcat 中的默认超时时间是 30 min。
超时时间属性为 maxInactiveInterval,可以通过对应的 getMaxInactiveInterval()
获取,通过 setMaxInactiveInterval(long interval)
修改。也可以在 web.xml (application.properties) 中修改。
另外,通过调用 Session 的 invalidate() 方法可以使 Session 失效。
Cookie
Cookie 是一段不超过 4KB 的小型文本数据,由一个 Name、一个 Value 和其它几个用于控制 Cookie 有效期、安全性、使用范围的可选属性组成。
Cookie 由服务器端生成,通过响应报文 (Set-Cookie) 发送给客户端。浏览器会将 Cookie 的 key/value 保存到某个目录下的文本文件内,下次请求同一网站时就发送该 Cookie 给服务器,以供其判断 web 状态信息。
Cookie 组成
- Name/Value:设置 Cookie 的名称(通常来讲 name 是不区分大小写的)及相对应的值。对于“认证Cookie”,Value 值包括 Web 服务器所提供的访问令牌 。
- Expires 属性:设置 Cookie 的生存期,这个值是 GMT 时间格式的。如果设置了 Cookie 将会被存储于磁盘中,如果没有则会被存储于浏览器内存中。
- Path 属性:定义了Web站点上可以访问该Cookie的目录。例如:
cookie.setPath(req.getContextPath + "/eg"); // => /工程路径/eg
- Domain 属性:指定了可以访问该 Cookie 的 Web 站点或域。Cookie 机制并未遵循严格的同源策略,允许一个子域可以设置或获取其父域的 Cookie。当需要实现单点(Single Sign On)登录方案时,Cookie 的上述特性非常有用,然而也增加了 Cookie 受攻击的危险,比如攻击者可以借此发动会话定置(Session Fixation)攻击。
- Secure 属性:设置了 Secure 属性的 cookie,只能通过 https 的方式来发送 cookies。使用 HTTPS 安全协议,可以保护 Cookie 在浏览器和 Web 服务器间的传输过程中不被窃取和篡改。
- HTTPOnly 属性 :设置了 HTTPOnly 属性,javascript 代码将不能操作 cookie。用于防止客户端脚本通过
document.cookie
属性访问 Cookie,有助于保护 Cookie 不被跨站脚本攻击窃取或篡改。
Cookie 过期属性
Max-age
document.cookie = 'foo=bar;path=/;max-age='+5*60+';';
Expires(需要指定具体日期繁琐)
var d = new Date();
d.setTime(d.getTime() + 5*60*1000); // in milliseconds
document.cookie = 'foo=bar;path=/;expires='+d.toGMTString()+';';
只需要设置一个,如果同时设置,Max-age 优先级更高,如果两个都不进行设置,该 cookie 将会是一个"session cookie",即 cookie 的有效时间为该会话,当浏览器关闭后 cookie 失效。
设置 cookie 失效
当服务端想让客户端删除一个 cocokie 时,会利用 Max-age 设置其过期 setMaxAge(int expiry)
,给客户端颁发一个同名 cookie(此时一般会将 value 设置成空白字符串)。注意!当 expiry
值为负数时(默认为 -1),cookie 会在浏览器关闭后删除;而当 expiry
值为 0 时, cookie 会被立刻删除。
Cookie 中存取中文
使用 URLEncoder 类里的 encode(String s, String enc) 方法进行中文转码
Cookie cookie = new Cookie("userName", URLEncoder.encode("孤傲苍狼", "UTF-8"));
在获取 cookie 中的中文数据时,再使用 decode(String s, String enc) 进行解码
URLDecoder.decode(cookies[i].getValue(), "UTF-8")
Cookie 应用实例
免登录
将账号、密码等登录信息保存在 cookie 中,并控制 cookie 的有效期,下次访问时再验证 cookie 中的信息即可。
方案一:把登录的时间戳保存到 cookie 与数据库中,再次访问时到数据库中验证用户名与登录时间戳即可。
方案二:把账号按照一定的规则加密后,连同账号一块保存到Cookie中。下次访问时只需要判断账号的加密规则是否正确即可。例如把账号保存到名为account的Cookie中,把账号用MD1算法加密后保存到名为ssid的Cookie中。验证时验证Cookie中的账号加密后是否与Cookie中的ssid相等。该方案只在登录时查询一次数据库,以后访问验证登录信息时不再查询数据库。
关于 Cookie & Session 失效的细节
- 如果客户的两次请求时间间隔长于了超时时间,那么 Session 失效。
- 如果 Cookie 没有设置过期时间,那么默认是关闭浏览器再删除。如此,在浏览器没有关闭之前, Session 可能已经失效,此时 name 为 "SessionID" 的 Cookie 虽然没被删除,但因为在后台找不到相应的对象,所有也不起作用了。如果再次访问服务端会重新颁发一个 SessionID 给 Cookie。(恰恰是由于关闭浏览器不会导致 Session 被删除,服务器才需要为 Session 设置了一个失效时间)
- 如果在 Session 超时时间内,关闭了浏览器,默认时效的 Cookie 会被删除。再次打开网页,即便是原 Session 还未被清除,但因为客户端丢失了 ID,只能在让服务端另外创建一个 Session 并发送其 ID 过来。
参考
https://mrcoles.com/blog/cookies-max-age-vs-expires/
https://baike.baidu.com/item/cookie/1119
https://www.cnblogs.com/l199616j/p/11195667.html