Cookie详解与跨域问题

Http是无状态的协议,客户端每次对服务端的http请求都是独立的,不受该客户端其它的请求的影响。

为了把Http这个无状态协议变的与上下文有关系,我们引入了会话(Session)的概念,具有相同会话ID的请求使之变成了有状态。

服务端可以给请求setSession的信息,信息保存在服务端内存,同时在response时将session内容推送给客户端浏览器,浏览器为了保存SessionID等信息,又有了Cookie这玩意,Cookie本质是一块存储少量数据的存储空间,可以存到内存也可以写入磁盘。每次浏览器向一个域名发送http请求时会去查找该域名的Cookie信息拼接到Httpheader中送到Server端。

 

谈到域名,可以简单的理解为我们访问的地址(请注意不是真正映射成的IP地址),而Cookie具有不跨域性质,只会将属于该域名的Cookie信息添加到Header中传到Server端。

下面我们写个Demo来试下Cookie的跨域

先设置下本机的host,添加两个域名peer1peer2

用管理员权限打开C:\WINDOWS\system32\drivers\etc\hosts

添加两行:

127.0.0.1       peer1

127.0.0.1       peer2

 

测试代码放在了 git 上:https://github.com/yejingtao/forblog/tree/master/cookie-domain

核心代码如下:

@Value("${cookie.value}")
    String cookieValue;
	
    @RequestMapping("/setCookie")
    public String home(HttpServletResponse response,HttpServletRequest request) {
    	Cookie cookie = new Cookie("testName", cookieValue);
    	response.addCookie(cookie);
        return "Success";
    }
    
    @RequestMapping("/getCookie")
    public String home(HttpServletRequest request) {
    	StringBuffer sb = new StringBuffer();
    	Cookie[] cookies = request.getCookies();
    	if(cookies!=null) {
    		for(Cookie cookie : cookies) {
    			sb.append(cookie.getName());
    			sb.append(",");
    			sb.append(cookie.getValue());
    			sb.append(";");
    		}
    	}
        return sb.length()==0?"Empty":sb.toString();
    }

测试前先看下我本机的cookie有哪些内容,需要对peer1peer2这两个域名做下清理:

Chrome浏览器为例:

设置--高级内容设置—cookie—查看所有cookie和网站数据,保证不要有peer1peer2cookie数据。

浏览器请求http://peer1:8087/setCookie,会发现cookie里多了peer1

打开箭头可以看到详细的cookie信息,cookie的属性有我们代码中显式设置的,也有隐式默认的:


此时我们请求peer1getCookie是可以获取到cookie值的,请求peer2getCookie是获取不到cookie内容的,所以验证了cookie是不能跨域的,而这个域是浏览器请求的域名,哪怕他们最终的服务端是一起的也不可以跨越。

上图中cookie值里有个域名peer1,这个不是我们代码中显式设置的,浏览器默认帮我们根据域名设置的,那么如果我显式设置一个跟域名对不上的domain会如何呢?

setCookie代码增加一行:

 @RequestMapping("/setCookie")
    public String home(HttpServletResponse response,HttpServletRequest request) {
    	Cookie cookie = new Cookie("testName", cookieValue);
    	cookie.setDomain("peer2");
    	response.addCookie(cookie);    	
        return "Success";
    }

清理浏览器cookie、重启服务后访问peer1setCookie

奇怪的是无论是peer1getCookie还是peer2getCookie都获取不到cookie内容,而且设置里面也确实没有。难道是浏览器自己的安全机制发现我setDomain与域名不匹配所以认为这是个无效的cookie就没有保存?调用下peer2setCookie就可以验证这一猜想,测试结果是肯定的。

Cookie是不安全的,浏览器、脚本类语言、甚至直接访问cookie保存文本的地址都可以获取到Cookie信息,所以尽量不要讲敏感内容保存在cookie中,即便是密码之类的可以进行加密,但是别人可以不需要解密直接使用你cookie中的内容进行欺骗。所以在服务端对cookie使用时,尽量设置超时时间,客户端尽量cookie不使用时(例如浏览器关闭)及时清空。

 

Cookie是客户端保存的内容,Session是服务端保存的内容,Session对于单个客户来说是安全的,而Cookie是客户共享的。所以可以推断得出从安全角度讲能用Session的情况尽量不要用Cookie,特别是现在Redis等共享缓存组件的使用使服务端存储Session的能力大大加强。


最后回到本文最开始的那张图,我们将代码再修改下验证下第一张图。

代码修改如下:

 

 @RequestMapping("/setCookie")
    public String home(HttpServletResponse response,HttpServletRequest request) {
    	request.getSession().setAttribute("sessionID", "haha");
        return "Success";
    }

请求后浏览器会保留一个cookie来存取sessionID







  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值