--转自开源中国
Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
一。Cookie
Cookie是什么?
Cookie是请求头域和响应头域的字段。简单地说,就是伴随请求和响应的一组键值对的文本,小文本。所以称之为”Cookie“饼干。 Cookie的生命来源于服务器。首先是客户端请求服务端,此时请求为第一次,无Cookie参数。这时候,服务端setCookie发送给客户端。记住,Cookie来源自服务端。Cookie有什么用呢?
Cookie来源自服务端,当然服务于客户。就像你我的会话,文字是在我们之间传递的。所以Cookie用于服务端和客户端的会话。因为Http协议是无状态的,Cookie就是维持会话,说白了就是传递数据的额外媒介。
@WebServlet(urlPatterns="/cookie")
public class CookieServletT extends HttpServlet
{
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// 获取Cookie
Cookie[] cookies = req.getCookies();
for (Cookie cookie : cookies)
System.out.println(cookie.getName() + " " + cookie.getValue());
// 创建Cookie
Cookie cookie = new Cookie("CookieName", "CookieValue");
cookie.setMaxAge(10);
cookie.setHttpOnly(true);
resp.addCookie(cookie);
// 响应
PrintWriter pw = resp.getWriter();
pw.print("<html><body><h1>Hello,Cookie!</h1></body></html>");
}
}
① 客户端访问,无服务端写入的Cookie。
代码 new Cookie(“CookieName”, “CookieValue”); 可以看出服务端产生一个新的键值对Cookie,并且设置,说明第一次请求时,请求的请求头域Cookie是没有的。下面没有CookieName=CookieValue 的Cookie值。如图:
② 服务端的Cookie传至浏览器。
代码中 HttpServletResponse.addCookie(cookie); 这样响应就加入了刚刚那个键值对Cookie。怎么传到浏览器(客户端)呢?
从图中可得到,Cookie是通过HTTP的响应头域发送至浏览器。每个Cookie的set,都有一个对应Set-Cookie的头。还有其中的时间代表Cookie的存活时间,HttpOnly可是此Cookie只读模式。
③ 浏览器解析Cookie,保存至浏览器文件。
直接可以打开IE的Internet选项:
如图,那个位置文件就是我们Cookie存的地方。
打开看看,其内容就是:存放着Cookie信息和URL信息及一些关于时间的。
CookieName
CookieValue
localhost/servletBYSocket/
9728
3416923392
30449698
3325104969
30449698
*
④ 客户端访问,有服务端写入的Cookie。
这样,同样的URL再次访问时,F12下:
⑤ 服务器获取
服务端这时呢?只要简单的 getCookies() 就可以获取Cookie列表了。如图,服务端控制台打印如下:
二。Session
HttpSession,保存跨一个特定用户多个请求的会话状态。关于服务端获取session,也就是从请求中获取session对象,容器会帮你根据Cookie找到唯一的session对象。what is Session?
Session代表着服务器和客户端一次会话的过程。直到session失效(服务端关闭),或者客户端关闭时结束。
How does session works?
Session 是存储在服务端的,并针对每个客户端(客户),通过SessionID来区别不同用户的。Session是以Cookie技术或URL重写实现。默认以Cookie技术实现,服务端会给这次会话创造一个JSESSIONID的Cookie值。
补充:
其实还有一种技术:表单隐藏字段。它也可以实现session机制。这里只是作为补充,服务器响应前,会修改form表单,添加一个sessionID类似的隐藏域,以便传回服务端的时候可以标示出此会话。 这技术,也可以使用在Web安全上,可以有效地控制CSRF跨站请求伪造。
@WebServlet(urlPatterns = "/sessionByCookie")
public class HttpSessionByCookieServletT extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 获取session
// 如果是第一次请求的话,会创建一个HttpSession,等同于 req.getSession(true);
// 如果已存在session,则会获取session。
HttpSession session = req.getSession();
if (session.isNew()) {
// 设置session属性值
session.setAttribute("name", "Jeff");
}
// 获取SessionId
String sessionId = session.getId();
PrintWriter out = resp.getWriter();
// 如果HttpSession是新建的话
if (session.isNew()) {
out.println("Hello,HttpSession! <br>The first response - SessionId="
+ sessionId + " <br>");
} else {
out.println("Hello,HttpSession! <br>The second response - SessionId="
+ sessionId + " <br>");
// 从Session获取属性值
out.println("The second-response - name: "
+ session.getAttribute("name"));
}
}
}
① 客户端向服务端发送第一次请求
此时,客户端想让服务端把自己的名字设置到会话中。
② 服务端的容器产生该用户唯一sessionID的session对象,并设置值
可以从代码中看出通过从请求中req.getSession(),新生成了一个session对象。并设置了setAttribute("name", "Jeff"),key为string,value是对象皆可。
这时候,我们不用再把session通过cookie技术处理,容器帮我们处理了。
③ 容器响应 Set-Cookie:JSESSIONID= ...
我们可以F12,查看此次响应。
从图中可得到,每个Cookie的set,都有一个对应Set-Cookie的头。HttpOnly可是此Cookie只读模式。只不过session唯一标识是:JSESSIONID
④ 浏览器解析Cookie,保存至浏览器文件。
如图,找到了对应的session存储的cookie文件。该文件被保护不能打开。
第二次请求会发什么变化呢?
下面,重新访问了这个地址:
① 再次请求
此时,请求会有Cookie值:JSESSIONID=… 该值传给服务端
② 容器获取SessionId,关联HttpSession
③ 此时响应无SetCookie
如图:
上图Bad guy,就是攻击者。跨站请求伪造,伪造用户请求来对服务器数据或者是用户等造成威胁。web安全也就是从这些基础中慢慢提升。