- 浏览: 5038 次
- 性别:
- 来自: 长沙
文章分类
- 全部博客 (6)
- JavaBase----Java基础 (1)
- DataBase----数据库 (0)
- HTML (0)
- XML (1)
- CSS (0)
- JavaScript (0)
- JSON (0)
- AJAX (0)
- DWR (0)
- EXTJS (0)
- JQuery (0)
- Servlet (0)
- Jsp (0)
- UML (0)
- Struts2.0 (1)
- IBatis (0)
- Hibernate (0)
- Spring (1)
- EJB3.0 (0)
- Frame Alignment----框架整合 (0)
- Design Patterns----设计模式 (0)
- RegExp----正则表达式 (0)
- AspectJ----AOP框架 (0)
- Oscache (0)
- JBPM----工作流 (0)
- Lucene----搜索引擎 (0)
- Linux----操作系统 (0)
- Tomcat、JBoss、Weblogic----服务器 (2)
最新评论
这里所说的跨域,是指跨二级域名,而且这些域名对应的应用都在同一个app上, 比如我有以下3个域名:
www.vinceruan.info
blog.vinceruan.info
bbs.vinceruan.info
我要在这三个域名直接共享cookie或者共享session,如何实现呢?在tomcat下又如何实现呢?
首先我们来了解下cookie,顾名思义,小甜心,少食即可,多吃无益。cookie是通过浏览器保存在客户端的临时数据,一般这些数据对安全的要求不高,虽然可以通过加密存放和SSL方式提交的方式加强cookie的安全,但不代表cookie就是百分之百安全的。再者,写入太多的cookie会造成数据管理的不可控,所以建议尽量少写cookie,像网易、新浪这些大型互联网公司,如果观察一下他们的站点,你会发觉他们会在浏览器写下大量的cookie,不过他们内部一般会有一套严格的cookie写入和清理的管理规定。比如网易邮件事业部就有这些规定。
cookie有两个很重要的属性:domain和path
domain告诉浏览器当前要添加的cookie的域名归属,如果没有明确指明则默认为当前域名,比如通过访问www.vinceruan.info添加的cookie的域名默认就是www.vinceruan.info,通过访问blog.vinceruan.info所生成的cookie的域名就是blog.vinceruan.info.
path告诉浏览器当前要添加的cookie的路径归属,如果没有明确指明则默认为当前路径,比如通过访问www.vinceruan.info/java/hotspot.html添加的cookie的默认路径就是/java/,通过blog.vinceruan.info/java/hotspot.html生成的cookie的路径也是/java/.
在清楚domain和path的生成规则后,我们需要知道浏览器在什么时候提交什么cookie到服务器,即浏览器是通过怎样的规则筛选cookie并提交到服务器的?
浏览器提交的cookie需要满足以下两点:
1.当前域名或者父域名下的cookie
而且
2.当前路径或父路径下的cookie
要满足以上两个条件的cookie才会被提交.举个例子:有4个cookie:
cookie1:[name=value, domain=.vinceruan.info path=/]
cookie2:[name=value, domain=blog.vinceruan.info path=/java/]
cookie3:[name=value, domain=www.vinceruan.info path=/]
cookie4:[name=value, domain=blog.vinceruan.info path=/]
当我访问blog.vinceruan.info时,
cookie1可以被提交,因为.vinceruan.info是blog.vinceruan.info的父域名. path路径也一致.
cookie2不能被提交,因为虽然domain是保持一致的,但是path不一致,当前访问的是/, 但是cookie2的path是/java/
cookie3不能被提交,因为虽然path是一致的,但是 www.vinceruan.info不是blog.vinceruan.info的父域名.
cookie4可以被提交,因为domain和cookie都严格保持一致.
这里需要注意的是, 在浏览器看来. www.vinceruan.info不是blog.vinceruan.info的父域名,而vinceruan.info才是blog.vinceruan.info的父域名, www.vinceruan.info也算是一个二级域名(这点如果你提交过域名到DNS服务器商的应该会知道,一般我们需要显式提交 www.vinceruan.info和vinceruan.info, 否则 www.vinceruan.info==vinceruan.info是不成立的).
所以如果我们需要在所有二级域名下共享islogin=1的cookie,用java代码如下:
Cookie c = new Cookie("islogin","1");
c.setDomain(" .vinceruan.info");//注意是以点号开头的.
c.setPath=("/");
response.addCookie(c);
如果要在所有的二级域名下的/java/路径下共享silogin=1的cookie,用java代码如下:
Cookie c = new Cookie("islogin","1");
c.setDomain(" .vinceruan.info");//注意是以点号开头的.
c.setPath=("/java/");
response.addCookie(c);
ok, 跨域共享cookie就完成了,比较容易,但是跨域共享session呢?
首先我们需要了解session机制的原理, session都是保存在服务器端的,而http连接是无状态的,那么服务器是如何在多次独立的http连接中为你维持同一个session呢?
这依赖于一个叫JSESSIONID的参数,这个参数可以从cookie或url获得,你如果你打开firebug,同时你的firefox是没有禁用cookie的,那么你刷新几次页面,你会看到浏览器提交的cookie中有一个叫JSESSIONID的key/value,这个就是会话ID,在这里你可以做一个试验,我们都知道firefox和IE 的cookie是不共享的,因此你在firefox下登录了,你用IE打开同一个网址,页面会显示你还处在未登录的状态,但是如果我在firefox下已经登录,并且拿到JSESSIONID的值,再到IE中输入url,并且加入JSESSION=.....的参数,你会发现,IE下也会显示我已经登录了。
这说明,如果我通过网络截除到了别人的JESSIONID,我就可以在服务器的会话还没过期前访问该站,如果对方还是处于登录状态的,我就可以修改对方资料甚至密码,多么可怕,当然这一切都是理论上的。
好了,一切都显得很顺利,要在不同的二级域名共享session,只需要把JESSIONID写进共享Cookie就行了。
可是,真的有这么容易么?
不同语言的实现手法不一样,听PHP方面的高手说是很容易实现的,可是java就比较难了,首先我们知道了request.getSession(true)的原理。
我这里tomcat为例,因为Java servlet api只是一套servlet接口规范,不同的java web容器实现的具体细节可能不同。
在tomcat中,当我们调用request.getSession(true)时,如果实际上新建了一个session,那么就会往浏览器写入一个JSEESIONID的cookie.这个cookie的domain属性是跟你当前站的域名是严格保持一致的,即类似于www.vinceruan.info或 blog.vinceruan.info而不是.vinceruan.info, 所以如果我们在session创建时就写入一个共享的cookie就行了.
可是这还是有困难:
1.如果我们在访问www.vinceruan.info新建了一个session的同时, 我写入一个JSESSIONID=****的、domain是.vinceruan.info的cookie, 理论上blog.vinceruan.info 也可以访问到在www.vinceruan.info这边创建的session了,但是很遗憾,如果我在访问www.vinceruan.info前先访问了blog.vinceruan.info, 同时创建了属于blog.vinceruan.info的session,这是再去访问www.vinceruan.info站点,同时建立了另一个session,并且建立了共享的JSESSIONID,这时再回去访问blog.vinceruan.info时,你会看到浏览器提交了两个JSESSIONID的cookie,类似于:
JSESSIONID=EXAD2AD5FA4D1A5D4 path =/ domain=blog.vinceruan.info
JSESSIONID=254SD2S5S1D2S5DS5 path = / domain=.vinceruan.info
可以看出,后者才是我手工创建的,而前者是tomcat创建的。很遗憾,我手工创建的不生效,因为tomcat在绑定session时,采取严格匹配更加优先的原则,blog.vinceruan.info比.vinceruan.info更加匹配。
所以问题已经转化为无论是那个应用,我要想办法在第一个创建session的应用中同时写入共享的JSESSIONID,即是说,我在写JSESSIONID到某个域下时,不允许这个域及其子域存在JSESSIONID不同值的情况。怎么解决呢?或许可以通过以下代码解决:
public Session getSession(HttpServletRequest request, HttpServletResponse response){
HttpSession session = request.getSession(false);
if (session==null){
session = request.getSession(true);
String session_id = session.getId();
Cookie c = new Cookie("JSESSIONID",session_id);
c.setDomain(".vinceruan.info");
c.setPath("/");
response.addCookie();
}
}
然后在所有应用中需要用到session的地方都调用这个方法,好像真的可以解决了,但是真的可以么?
还是有问题:
1.如果我已经往response里面输出body内容了,而这时调用这个方法请求session,且session是第一次被创建时会有问题。
2.对于我调用的第三方代码,比如spring,它们里面调用session的方式不是我能控制的。
好的,这个方法已经明显不行了。
还有一个HttpSessionListener, 它里面还有一个sessionCreated(SessionEvent event)的回调方法,无论是在什么代码中新建session,这个回调接口是一定会被调用的,但是,我拿不到HttpServletResponse句柄.所以这个方法还是不行.
我没有用SSO,是因为我这个应用的需求很简单,就是共享登录状态,而且就一个应用,只不过对应到不同的域名而已,所以没有必要用那么重量级的东西。
最后的修改是为tomcat增加一个Valve,同时注册到server.xml中去,这种方式也不太好,因为跟tomcat耦合了,但是也是目前可以想到的比较好的一个方法了。
首先新建一个类:
public class SessionCrossDomainValve extends ValveBase {
public SessionCrossDomainValve() {
super();
info = "com.jinfuzi.SessionCrossDomainValve";
}
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
request.getSession(true);
// replace any Tomcat-generated session cookies with our own
Cookie[] cookies = response.getCookies();
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies;
containerLog.debug("CrossSubdomainSessionValve: Cookie name is "
+ cookie.getName());
if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName())) {
replaceCookie(request, response, cookie);
}
}
}
// process the next valve
getNext().invoke(request, response);
}
@SuppressWarnings("unchecked")
protected void replaceCookie(Request request, Response response, Cookie cookie) {
//copy the existing session cookie, but use a different domain
Cookie newCookie = new Cookie(cookie.getName(), cookie.getValue());
if (cookie.getPath() != null)
newCookie.setPath(cookie.getPath());
newCookie.setDomain(getCookieDomain(request));
newCookie.setMaxAge(cookie.getMaxAge());
newCookie.setVersion(cookie.getVersion());
if (cookie.getComment() != null)
newCookie.setComment(cookie.getComment());
newCookie.setSecure(cookie.getSecure());
//if the response has already been committed, our replacement strategy will have no effect
if (response.isCommitted())
containerLog.error("CrossSubdomainSessionValve: response was already committed!");
//find the Set-Cookie header for the existing cookie and replace its value with new cookie
MimeHeaders headers = response.getCoyoteResponse().getMimeHeaders();
for (int i = 0, size = headers.size(); i < size; i++)
{
if (headers.getName(i).equals("Set-Cookie"))
{
MessageBytes value = headers.getValue(i);
if (value.indexOf(cookie.getName()) >= 0)
{
StringBuffer buffer = new StringBuffer();
ServerCookie.appendCookieValue(buffer, newCookie.getVersion(), newCookie
.getName(), newCookie.getValue(), newCookie.getPath(), newCookie
.getDomain(), newCookie.getComment(), newCookie.getMaxAge(), newCookie
.getSecure()); //如果是tomcat6.020,这里需要多加一个true.
containerLog.debug("CrossSubdomainSessionValve: old Set-Cookie value: " + value.toString());
containerLog.debug("CrossSubdomainSessionValve: new Set-Cookie value: " + buffer);
value.setString(buffer.toString());
}
}
}
}
protected String getCookieDomain(Request request) {
String cookieDomain = request.getServerName();
String[] parts = cookieDomain.split("\\.");
if (parts.length >= 2)
cookieDomain = parts[parts.length - 2] + "."
+ parts[parts.length - 1];
return "." + cookieDomain;
}
public String toString() {
return ("CrossSubdomainSessionValve[container=" + container.getName() + ']');
}
}
将这个类打包成jar包,放进{catalina_home}/lib下,并在server.xml中注册:
<Valve className="SessionCrossDomainValve"/>
相关推荐
综上所述,解决Spring Boot中的跨域session共享问题和防止SQL注入,需要结合CORS配置、分布式session存储和安全编程实践。通过合理的配置和编程习惯,我们可以构建更加健壮、安全的Web服务。提供的压缩包文件`...
标题中的“跨域共享session”是指在Web开发中,如何在不同的域名或协议(如HTTP和HTTPS)之间共享用户登录状态。...实现HTTP到HTTPS的session共享需要综合考虑这些因素,并确保在提供便利的同时,保证用户数据的安全。
这是因为浏览器的同源策略(Same-Origin Policy)限制了不同源之间的交互,包括`session`和`cookie`。 同源策略是Web安全的核心机制,防止恶意网站通过脚本访问其他网站的敏感数据。然而,这在某些场景下会带来不便...
该文件可以通过代码实例,让你清楚的理解session和cookie的意思,当你明白了这点,你就可以设计出来单点登录功能,同一账号在同一时间只能登录一次功能。同时你可以通过ie、firefox去测试你对session、cookie的理解...
在现代Web应用开发中,数据共享和跨域访问是常见的需求。Spring Boot作为一个轻量级的框架,提供了方便快捷的方式来实现这些功能。本教程将详细讲解如何在Spring Boot项目中利用Redis来存储和共享Session,并解决...
Redis作为一个高性能的Key-Value数据库,对于存储和检索Session数据非常高效,是实现Session跨域共享的理想选择。在实际项目中,可以根据具体需求调整配置和实现细节,以达到最佳性能和安全性。
- **性能考量**:跨域session可能会增加网络负载,因为session数据需要在多个服务器之间同步。因此,优化session数据大小和减少不必要的同步操作是必要的。 - **兼容性**:不同浏览器对于cookie的处理方式可能有所...
在"Share ASP.NET sessions between domains (高版本可用的CMOdel)"的压缩包中,包含了一个已经实现跨域Session共享的模型(CModel)。你可以直接使用这个模型作为起点,进行自己的项目集成。该模型可能包含了必要的...
本项目"基于Cookie的Session跨域"则关注如何在分布式环境中解决Session的共享问题,通过Spring和Spring MVC框架来实现这一目标。 首先,我们来了解一下Cookie和Session的基本概念。Cookie是由服务器端发送到客户端...
`,可以让浏览器接受跨域Cookie。 2. **统一Session存储**: - **数据库存储**:文中提供的`Session`类示例展示了如何将Session数据存储在MySQL数据库中。这种方法适用于多台服务器或跨域情况,因为数据存储在集中...
本文将深入探讨如何使用PHP实现Cookie跨域和Session共享,以及处理相关问题的方法。 首先,让我们理解Cookie和Session的基本概念。Cookie是由服务器发送到客户端(浏览器)并由客户端保存的一小段数据,通常用于...
在Web开发中,Iframe(内联框架)常用于嵌入其他网页内容,但涉及到跨域访问时,尤其是在处理Cookie和Session时,会遇到一些挑战。本文主要探讨如何解决Iframe跨域访问Cookie和Session的问题。 首先,理解跨域访问...
在前后端分离的架构中,Vue.js作为前端框架与Spring Boot作为后端服务进行交互时,常常会遇到跨域和Session、Cookie失效的问题。本文将详细介绍如何解决这些问题。 首先,跨域是由于浏览器的安全策略限制,同一源...
ThinkPHP框架实现session跨域问题的解决方法主要涉及到了两个方面:其一,是PHP自身处理session...同时,还应该了解session.cookie_domain的具体设置方法及其对session共享范围的影响,以实现安全和高效的session管理。
通过在客户端存储Session ID,并在请求中携带,可以实现在不同协议间的Session共享。然而,必须采取适当的加密和安全措施,以防止Session ID被恶意利用。上述代码示例提供了一个基本的实现方案,但在实际应用中,应...
6. **第三方服务**:利用第三方服务(如Auth0、Okta等)进行统一身份认证和会话管理,这些服务通常提供跨域Session共享的功能。 在实际应用中,选择哪种方法取决于项目的需求、规模、安全性考虑以及现有基础设施。...
在基于Cookie的二级域名下跨域共享SSO实现中,核心概念是利用Cookie的特性来实现用户身份的共享与传递。 首先,我们了解SSO的工作原理。当用户首次访问一个应用系统(例如,`app1.example.com`)时,如果用户尚未...
### Cookie、Session与Token的区别及使用详解 #### 一、Cookie **定义**: Cookie是一种用于在客户端保持状态的方案。简单来说,当你访问一个网站时,该网站可能会在你的计算机上留下一些信息(如用户名、密码等),...
在Web开发中,Cookie和Session是两种常见的用户身份验证机制,尤其在C#编程语言中,它们被广泛用于实现登录功能。本实例将探讨如何在C#环境下利用Cookie和Session来处理用户登录状态。 首先,我们要理解Cookie和...
本文将深入探讨SpringSession如何支持Cookie和header策略,并解析`CookieHeaderHttpSessionStrategy.java`这个文件中的关键概念和技术细节。 首先,我们来看标题提及的“SpringSession同时支持Cookie和header策略”...