Web应用跨域访问解决方案汇总
wuqinheli
13年前
<p> 做过跨越多个网站的Ajax开发的朋友都知道,如果在A网站中,我们希望使用Ajax来获得B网站中的特定内容,如果A网站与B网站不在同一个域中,那么就出现了跨域访问问题。Ajax的跨域访问问题是现有的Ajax开发人员比较常遇到的问题。<br> IE对于跨域访问的处理是,弹出警告框,提醒用户。如果用户将该网站纳入可信任网站,或者调低安全级别,那么这个问题IE就不会在提醒你。<br> FireFox等其它非微软的浏览器遇到跨域访问,则解决方案统一是拒绝访问。<br> 有人说,IE是主流浏览器,只要它能正常使用就好了。此言差已,IE虽然能够处理,但是是有前提的,要么用户不厌其烦地在页面弹出警告框之后点击是(点击否就不执行该Ajax调用了),要么用户将该网站纳入可信任站点。这两种做法,在企业管理系统的应用中倒是比较常见,因为系统管理员可以以行政手段保证用户的行为。但是对于互联网上的网站或者门户开发,这种做法则不行。</p> <p>最近遇到了这个问题,需要在跨域访问结束之后完成使主窗口出现一些特效,搜索了一些资料,通过不断尝试以及在不同浏览器中进行兼容性测试,找到了几个可行的Web应用跨域访问解决方案:<br> <strong>1、Web代理的方式。</strong></p> <p>即用户访问A网站时所产生的对B网站的跨域访问请求均提交到A网站的指定页面(Post页面过去),由该页面代替用户页面完成交互,从而返回合适的结果。此方案可以解决现阶段所能够想到的多数跨域访问问题,但要求A网站提供Web代理的支持,因此A网站与B网站之间必须是紧密协作的,且每次交互过程,A网站的服务器负担增加,且无法代用户保存session状态。</p> <p><br> <strong>2、on-Demand方式。</strong></p> <p>MYMSN的门户就用的这种方式,不过MYMSN中不涉及跨域访问问题。动态控制script标记的生成,通过修改script标记的src属性完成对跨域页面的调用。此方案存在的缺陷是,script的src属性完成该调用时采取的方式时get方式,如果请求时传递的字符串过大时,可能会无法正常运行。不过此方案非常适合聚合类门户使用。</p> <p><br> <strong>3、iframe方式。</strong></p> <p>查看过醒来在javaeye上的一篇关于跨域访问的帖子,他提到自己已经用iframe的方式解决了跨域访问问题。数据提交跟获取,采用iframe这种方式的确可以了,但由于父窗口与子窗口之间不能交互(跨域访问的情况下,这种交互被拒绝),因此无法完成对父窗口效果的影响。</p> <p><strong>4、用户本地转储方式。</strong></p> <p>IE本身依附于windows平台的特性为我们提供了一种基于iframe,利用内存来“绕行”的方案,即两个window之间可以在客户端通过windows剪贴板的方式进行数据传输,只需要在接受数据的一方设置Interval进行轮询,获得结果后清除Interval即可。FF的平台独立性决定了它不支持剪贴板这种方式,而以往版本的FF中存在的插件漏洞又被fixed了,所以FF无法通过内存来完成暗渡陈仓。而由于文件操作FF也没有提供支持(无法通过Cookie跨域完成数据传递),致使这种技巧性的方式只能在IE中使用。</p> <p><br> <strong>5、我自己用于解决这类问题的方式.</strong></p> <p>结合了前面几种方式,在访问A网站时,先请求B网站完成数据处理,再根据返回的标识来获得所需的结果。这种方法的缺点也很明显,B网站的负载增大了。优点,对session也实现了保持,同时A网站与B网站页面间的交互能力增强了。最重要的一点,这种方案满足了我的全部需要。<br> 总结一下,以上方案中可选择的情况下,我最推荐on-Demand方式,在不需要提交大量数据的情况下,这种方式能够解决您的大部分问题。</p> <p> </p> <p>==========================================================</p> <p><br> <strong>跨平台跨服务器跨网站SSO(单点登录)的方案</strong></p> <p>最近在研究SSO,看到各种复杂的解决方案觉得很疑惑,自己想出了个简单有效的方案,大家来评评有什么问题吗?<br> 服务器A:网站A<br> 服务器B:网站B<br> 服务器C:验证网站(验证表中有UID和KEY两个字段)。</p> <p>1. 用户打开网站A的页面http://服务器A/a.aspx,检测发现网站Session中没有存储用户名UID。</p> <p>2. 系统转到验证服务器登录页面,并在QUERYSTRING中附加前一个页面的URL地址。比如http://服务器C/login.asp?URL=http://服务器A/a.aspx</p> <p>3. 在验证服务器登录成功后更新验证服务器的Session(超时设置为足够长,比如1天)。然后生成一个GUID值,写入验证表。最后,把这个GUID值和UID保存到一个类中序列化后附加在URL中返回网站A的那个页面。</p> <p>比如http://服务器A/a.aspx? token=sadhsagdkjasgyugd7d8yweihasdiuhagsdiuashdhaiushdi</p> <p>4. 网站A的页面读取QUERYSTRING,然后反序列化出一个类,读取类的UID和KEY信息。然后,从数据库中查找匹配的记录,如果找到了则表明登录成功,并把这条记录的KEY更新成另外一个GUID(这样就保证了即使这个URL被别人拿走再登录都不能成功)。把UID写入服务器A的Session中即可。</p> <p>5. 用户打开网站B的页面http://服务器B/b.aspx,服务器B上没有当前用户的Session信息,自动转向验证服务器检测是否存在Session,如果找到了表明用户已经登录过,再重复步骤3和4,如果没有找到就转到验证服务器的登录页面。<br> 巧妙之处在于:</p> <p>l 网站服务器和验证服务器都拥有一份和用户关联的Session,验证到时候不需要传任何和UID相关的信息,因此也可以跨服务器。正因为如此不需要使用cookie也解决了跨域名。</p> <p>l 网站服务器和验证服务器可以使用自己的状态机制(不一定是Session),因此跨平台也没有问题。</p> <p>l 用于验证用户的TOKEN使用GUID在每次验证的时候都会更换,而且GUID和UID是捆绑在一起的,即使GUID碰巧对上了也不知道这个GUID对应了哪个UID。</p> <p>l 通过验证服务器的验证后,服务器发回的token数据经过了序列化,用户很难伪造。<br> (实在不放心还可以对这个token进行加密)<br> 不知道大家是否理解了?<br> 更新:经过网友提醒,我想到这个方案在登出的时候有严重问题,比如A网站登出了,我们不能通知其它网站该用户已经登出,它再切换到其它网站又是登录状态(因为Session没有过期),不过我也想到了一个解决方案。就是所有的网站都有一个专门的页面或者服务,根据传过来的令牌来清空这个当前用户的Session。登出以后把所有网站的Session都清空,如果网站不是很多的情况下还好,网站一多登出就会很慢了!<br> 更新:现在看来已经没有什么问题了,到时候放出完整DEMO!<br> 更新:有网友不理解为什么关闭浏览器所有网站退出登录?因为Session是和用户浏览器实例关联的,而我们所有网站都使用Session,因此关闭了浏览器所有网站都退出了。这个和退出登录按钮不一样,退出登录按钮需要发通知让所有网站清除Session。<br> 更新:我们现在把这个框架的登录放到了各个网站中,保证登录和退出在登录服务器Down的情况下也能进行,只是不能进行跨站登录罢了。登录服务器Down还能实现本站登录和退出。过几天放出完整源代码!</p> <p><br> ==========================================================</p> <p> </p> <p>单点登陆问题-实现单点登陆的几种方法<br> 1 可以实现单点登陆的几种方法</p> <p>(1)基于domain的方案<br> 这种方案是我公司目前使用的一种方案,原理:应用A在a.domain.com,B在b.domain.com,如果设cookie的时候,设domain为domain.com,那在A、B上都可以访问到这个cookie了。(cookie的domain、path、port、version、secure相同)。<br> 该方案特点:<br> 1、不能够跨域<br> 2、在网络中传送用户名和密码<br> 3、只支持J2EE应用<br> (2)基于gateway的方案<br> 实际部署的时候,对所有应用的请求,都要通过一个gateway转发一下,比如用一个L4的交换机顶在前面。<br> (3)基于tooken传递的方案<br> 主要是以耶鲁大学的CAS项目为基础。<br> 注意:你自己的应用看不到用户的密码。由CAS执行授权,只有CAS能看到用户的密码。这样增加发安全性,因为用户名和密码不会通过网络在应用间传播。<br> 下面是使用CAS整合的单点登录用例<br> 用例一:<br> 一台认证服务器(假定为AUTH),有两个应用A、B,分别部署在不同的服务器上。<br> 1) 用户访问A,A应用无法找到用户的身份信息,使用redirect方法将用户引导至http://Auth/login?service=http://A/path。<br> 2) AUTH 显示登录界面,用户输入登录信息,认证通过。<br> 3) AUTH产生一个cookie(这个cookie只有AUTH上才能读到),使用redirect方法将用户引导回http://A/path?token=xxxxx(在有的解决方案上,这个token是通过一定编码算法的Account信息)<br> 4) A读取token=xxxx的信息,获取用户身份。<br> 5) 用户访问B。B未找到用户的身份信息,redirect至http://AUTH/login?service=http://B/path<br> 6) AUTH读cookie获取用户身份,然后redirect回http://B/path?token=xxxx<br> 7) B读取token=xxxx信息,获得用户身份信息<br> 用例二:<br> 用户访问一个Web应用的过程。</p> <p><a href="https://simg.open-open.com/show/4511101cf72c19fa638f4898f09d9173.gif"><img alt="" src="https://simg.open-open.com/show/4511101cf72c19fa638f4898f09d9173.gif"></a></p> <p>具体的参看 http://www.9ta8.com/YaleCASServer.mht<br> (4)USBKey登录<br> 这个方案是北京点聚信息技术有限公司提供的,我也向他们的技术咨询了相关的问题。他们的实现方式基本上是这样的:每个使用该系统的用户都有一个USBKey证书,在登陆系统的时候把这个证书插在计算机上。每一个网站都要通过这个证书去认证。<br> 这样每个登录用户只需插上USBKey即可进入任意受信任系统,当然访问USBKey首先需要密码校验。<br> 2 个人认为单点登陆实际上就两种方案<br> 首先确认要使用单点登陆,必须有一个核心,那就是不管用户走到那个平台,他必须要带着他的通行证,单点登陆最关键的问题是用户怎么取得、保存、使用这个通行证的问题。 用户要取得他的通行证其实不外乎以下两种方案:<br> 第一种:所有的业务平台集成在一个Portal上,去每一个平台的时候都要带着他的“通行证”,这就是所谓的“Tooken传递方案”;<br> 第二种:使用硬件卡,就是上面所说的“USBKey登陆”;<br> 3 单点登陆的几个案例<br> (1)微软一篇关于单点登陆的文章,他的实现是使用第一种方案。<br> 原文:</p> <p>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/singlesignon.asp</p> <p>(2)SharePoint Portal Server 2003 中的单一登录</p> <p>http://www.microsoft.com/china/technet/prodtechnol/sppt/reskit/c2661881x.mspx</p> <p>(3)《WebCast SharePoint Portal Server 2003 Single Sign On 管理及开发》已提供下载</p> <p>http://www.msotec.net/Forums/ShowThread.aspx?PostID=415</p> <p>4 单点登陆的参考方法<br> 服务器端可控JS跨域访问解决方法</p> <p>http://bbs.ad0.cn/viewthread.php?tid=302&extra=page%3D1</p> <p>SSO – Single Sign-On Enterprise Security for Web Applications</p> <p>http://bbs.ad0.cn/viewthread.php?tid=304&extra=page%3D1</p> <p>单点登录的简单实现</p> <p>http://bbs.ad0.cn/viewthread.php?tid=305&extra=page%3D1</p> <p>PHP实现WebServices和跨域自动登陆</p> <p>http://bbs.ad0.cn/viewthread.php?tid=307&extra=page%3D1</p> <p>Passport跨域认证解决方法</p> <p>http://bbs.ad0.cn/viewthread.php?tid=309&extra=page%3D1</p> <p>Web应用跨域访问解决方案</p> <p>http://bbs.ad0.cn/viewthread.php?tid=310&extra=page%3D1</p> <p>Flex或Flash的跨域访问解决方案</p> <p>http://bbs.ad0.cn/viewthread.php?tid=313&extra=page%3D1</p> <p>跨域访问新方案-PHPRPC</p> <p>http://bbs.ad0.cn/viewthread.php?tid=315&extra=page%3D1</p> <p>==========================================================<br> PHP使用P3P完成跨域COOKIE操作[转载]<br> 实际工作中,类似这样的要求很多,比如说,我们有两个域名,我们想实现在一个域名登录后,能自动完成另一个域名的登录,也就是PASSPORT的功能。<br> 为了测试的方便,先编辑hosts文件,加入测试域名(C:\WINDOWS\system32\drivers\etc\hosts)<br> 127.0.0.1 www.a.com<br> 127.0.0.1 www.b.com<br> 首先:创建 a_setcookie.php 文件,内容如下:<br> <?php<br> //header(‘P3P: CP=”CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR”‘);<br> setcookie(“test”, $_GET['id'], time()+3600, “/”, “.a.com”);<br> ?><br> 然后:创建 a_getcookie.php 文件,内容如下:<br> <?php<br> var_dump($_COOKIE);<br> ?><br> 最后:创建 b_setcookie.php 文件,内容如下:<br> <script src=”http://www.a.com/a_setcookie.php?id=www.b.com”></script><br> ----------------------------<br> 三个文件创建完毕后,我们通过浏览器依次访问:</p> <p>http://www.b.com/b_setcookie.php</p> <p>http://www.a.com/a_getcookie.php</p> <p>我们会发现,在访问b.com域的时候,我们并没有在a.com域设置上cookie值。<br> 然后我们修改一下a_setcookie.php文件,去掉注释符号,a_setcookie.php即为:<br> <?php<br> header(‘P3P: CP=”CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR”‘);<br> setcookie(“test”, $_GET['id'], time()+3600, “/”, “.a.com”);<br> ?><br> 再次通过浏览器依次访问:</p> <p>http://www.b.com/b_setcookie.php</p> <p>http://www.a.com/a_getcookie.php</p> <p>这次,你会发现在访问b.com域的时候,我们设置了a.com域的cookie值。</p> <p>==========================================================<br> 跨域(cross-domain)访问 cookie (读取和设置)[转,保存][转载]</p> <p>Passport 一方面意味着用一个帐号可以在不同服务里登录,另一方面就是在一个服务里面登录后可以无障碍的漫游到其他服务里面去。坦白说,目前 sohu passport 在这一点实现的很烂(不过俺的工作就是要把它做好啦,hehe)<br> 搜狐的 SSO 需求比较麻烦,因为它旗下有好多域名:sohu.com、chinaren.com、sogou.com、focus.cn、17173.com、go2map.com,登录用户漫游的主要障碍也来自于此。<br> 以前亿邮的邮件系统在和别的系统整合的时候是提供一个 URL,用户从第三方系统里面点击这个链接就可以生成访问邮件界面所需的 cookie,然后进入邮件。这个方式的确很有效,但问题是:<br> 1. 每个外部链接都必须用特殊的 URL 跳转,维护很麻烦<br> 2. 两个系统集成已经很麻烦了,若是集成的系统有好几个,彼此都需要跳转而缺乏一个中心机制就成了噩梦<br> 3. 根本无法处理用户直接在地址栏输入地址进行访问的情况<br> 即使是跨域,上述的解决方法相对来说还是容易的。<br> A. 首先是所有登录必须首先通过一个中央服务器进行认证,然后在它那里给浏览器种下 cookie(下面称之为 sso cookie)<br> B. 当用户访问另外的域名 app 的时候,浏览器是无法直接发送 sso cookie 给服务器认证的。此时应该利用 ,动态创建一个隐藏的 ,让其访问 sso<br> C. 这个 i 的请求是可以把 sso cookie 送给 sso server 的。sso server 验证 cookie 后,返回一个重定向页面到 app 的某个 URL,由该 URL 设置 app cookie<br> D. 此时浏览器上可看见的页面容器实际上也是可以和重定向回来的内容交互的。比如可以用 js 控制发现重定向页面成功返回后,就刷新整个页面,让它看起来和用户登录后访问没有什么区别。<br> 下面是真正的技巧:怎样才能在 IE 里面跨域去设置 cookie<br> 上述技术看起来是不是很好?但它的前提是所有的登录都 post 到 sso server 上,认证成功后再返回 app 页面。可我接受到的需求之一就是要支持页面无刷新登录。<br> 哈!就是说本来在 chinaren.com 上提交登录表单的 action 应该是 passport.sohu.com 这个 sso server。可是在 AJAX 大潮下,chinaren 计划采用 HTTPRequest 提交,这个就麻烦了,因为是不能跨域来提交的。<br> 那么解决方法就是跨域产生 cookie,即 js 发现口令校验成功后,再在 passport.sohu.com 上种上合法的 cookie.<br> 套用上面的跨域读 cookie 的方案似乎很简单去推论:就是创建一个隐含的 iframe,让那个 iframe 去调用 passport.sohu.com 的 URL 来产生 cookie。很遗憾,此方法在 Fx 下工作的很好,但是不能在 IE 上应用。(在 IE 状态栏上显示 cookie 隐私警告,红色圆底白横杠)<br> 我试了很多很多方法,包括创建 、 node,包括用 js 设置,但都一次次被 IE 无情的挡在了浏览器外。google 之,也没有任何真正可用的答案,中文网页要么介绍的方法是错的,要么说无解。<br> 最后还是在 chinaren 一哥们的帮助下,翻出了他们所使用的,以和 alumni.sohu.com 交互的方法(不知道是哪位牛人发现的),只需要设置 P3P HTTP Header,在隐含 iframe 里面跨域设置 cookie 就可以成功。他们所用的内容是:<br> P3P: CP=’CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR’<br> 最后是我做的一个小小的演示:cookie 怎么在 vmx.cn 和 dup2.net 之间交互<br> 1. http://qiuyingbo.test.vmx.cn/cookie.php<br> 2. 随便输入什么,点 reset cookie,就可以看到 vmx.cn 的 cookie 已经被设上了<br> 3. 在该页面点连接到 http://www.dup2.net/vmx/cookie.html<br> 4. 点’get corss-domain cookie’ .. (此时 js 会去创建一个iframe,请求 qiuyingbo.test.vmx.cn ,返回页面把 cookie 值作为 GET 参数重定向回 dup2.net 的另外一个URL。)<br> 5. 点 ‘display corss-domain cookie’ .. 就可以看到 vmx.cn 的 cookie 了<br> 6. 在该页面的输入框中输入其它的值,然后点 ’set cross-domain cookie’,该行为将主动设置 vmx.cn 的 cookie<br> 7. 点链接回到 http://qiuyingbo.test.vmx.cn/cookie.php ,就可以看到新的值了<br> 通过设置P3P头来实现跨域访问COOKIE</p> <p>==========================================================</p> <p>单点登录的简单实现<br> SSO 单点登录的简单实现 实现门户网站单点登录<br> 在门户项目中,经常会遇到如何实现单点登录的问题,下面就本人的经验做个总结。欢迎大家进行补充讨论。<br> 单点登录的具体实现有很多种选择,包括:<br> 采用专门的SSO商业软件: 主要有:Netgrity的Siteminder,已经被CA收购。Novell 公司的iChain。RSA公司的ClearTrust等。<br> 采用门户产品供应商自己的SSO产品,如:BEA的WLES,IBM 的Tivoli Access Manager,Sun 公司的identity Server,Oracle公司的OID等。<br> 这些商业软件一般适用于客户对SSO的需求很高,并且企业内部采用COTS软件如:Domino,SAP,Sieble的系统比较多的情况下采用。并结合身份管理。统一认证等项目采用。采用这些软件一般都要对要集成的系统做些改造,如在要集成的系统上安装AGENT。现在一般只提供常见软件如:Domino,SAP,Sieble,常见应用服务器:weblogic,websphere等的AGENT。要先统一这些系统的认证。一般采用LDAP或数据库。然后才能实现SSO。比较麻烦。<br> 另外,如果不想掏银子,也有OPEN SOURCE的SSO软件可选:主要有:http://www.josso.org/ https://opensso.dev.java.net/ http://www.sourceid.org 等。具体怎么样就不清楚了。</p> <p>==========================================================</p> <p>在PHP中实现单点登录(Single Sign On)的一种简单方法<br> 单点登录是大容量系统必备的功能,市面上有几款昂贵的商业系统,若不是财大气粗,恐怕用不起。<br> 怎么样才能简单、经济的实现这个功能?我们在这里探讨一种可行的方案。<br> 当前开发Web应用中,Apache + PHP + MySQL是中小型企业降低成本的必选架构,这里我们来实现PHP的单点登录,让这种经济性的架构能够扩展到的群集服务器层面。<br> 我们的设想是将PHP的Session数据集中存储,这样对于不同服务器中运行的PHP来说,只有一个共有的Session数据库,那么用户在服务器A登录所生成的Session数据在服务器B、C、D等服务器都可以共享,就可以免除多次登录。但由于PHP的Session是需要Cookie的,而Cookie又是与域名相关的,所以采用这个方案的各个服务器需要有相同的域名(至少是相同的二级域名),比如:<br> 1、所有服务器的域名都是www.whybsd.com,这个东东DNS轮询就可以实现;这个时候,在PHP中将Cookie域名设置为www.whybsd.com即可;<br> 2、所有服务器的域名都是以.whybsd.com结尾的三级域名,比如a.whybsd.com,b.whybsd.com等等,这个时候,在PHP中将Cookie域名设置为.whybsd.com就可以共享Cookie了。<br> 解决了先决条件,我们现在来看看PHP的Session存储方法,在PHP手册说明中,有一个叫session_set_save_handler()的函数,这个函数是用来注册用户自定义的Session数据存储接口的。<br> 以下是PHP手册自带的示例:<br> 代码:</p> <p><?php<br> function open($save_path, $session_name) {<br> global $sess_save_path, $sess_session_name;</p> <p>$sess_save_path = $save_path;<br> $sess_session_name = $session_name;<br> return(true);<br> }<br> function close() {<br> return(true);<br> }<br> function read($id) {<br> global $sess_save_path, $sess_session_name;<br> $sess_file = “$sess_save_path/sess_$id”;<br> if ($fp = @fopen($sess_file, “r”)) {<br> $sess_data = fread($fp, filesize($sess_file));<br> return($sess_data);<br> } else {<br> return(“”); // Must return “” here.<br> }<br> }<br> function write($id, $sess_data) {<br> global $sess_save_path, $sess_session_name;<br> $sess_file = “$sess_save_path/sess_$id”;<br> if ($fp = @fopen($sess_file, “w”)) {<br> return(fwrite($fp, $sess_data));<br> } else {<br> return(false);<br> }<br> }<br> function destroy($id) {<br> global $sess_save_path, $sess_session_name;</p> <p>$sess_file = “$sess_save_path/sess_$id”;<br> return(@unlink($sess_file));<br> }<br> /*********************************************<br> * WARNING – You will need to implement some *<br> * sort of garbage collection routine here. *<br> *********************************************/<br> function gc($maxlifetime) {<br> return true;<br> }<br> session_set_save_handler(“open”, “close”, “read”, “write”, “destroy”, “gc”);<br> session_start();<br> // proceed to use sessions normally<br> ?></p> <p>按照这种思路,我们只要编写自己的处理函数并进行相应的注册,就可以实现PHP Session数据的自定义存储了。<br> 具体实现可以开动你的思路,比如可以使用NFS将Session数据存储到统一的网络设备中,也可以将Session数据保存到一个数据库中,让所有服务器连接这个共享数据库(比如MySQL)就可以了。<br> 嗯,比较简单,而且经济。<br> 更多考虑:<br> 1、性能需要考量,特别是服务器数(引起资源占用)和用户量(引起Session量)非常巨大的时候。<br> ==========================================================<br> PHP实现WebServices和跨域自动登陆<br> 1、webservices的php实现<br> 主要是基于nusoap这个库来实现的,其不但可以实现server功能还可以实现client功能,支持end point和WSDL两种方式;连soap协议的xml消息都是自己解析的,所以完全可以脱离其他php库支持;优点之一啊;可惜,可能有性能上的忧虑。<br> 2、session跨域自动登陆<br> 了解http协议特性的人都知道(参考RFC),服务端session只能是通过cookie或者get、post方法传递的unique id来实现的;因此欺骗服务端session的行为理论上是很容易实现的,只要你知道那个unique id及传递的方式;而在某个session创建之后,只要传递给其该唯一标示,其都是可以被认可为会话客户的;因此,在获得会话id的前提下任何跨域session访问都是可能的。通过get、post方式的id容易拿到和创建,而通过cookie传递的就必须突破浏览器的跨域cookie创建限制,当然如果需要实现跨域session创建的是可控制的服务端,那问题就迎刃而解了(不过该条件下的解决方案有多种,例如互连星空就使用的URL转向方法)。PHP实现WebServices和跨域自动登陆具体例子就不详述了。<br> ==========================================================<br> Passport跨域认证解决方法<br> 非常简单的Passport跨域认证解决方法:<br> 1、架设一个PASSPORT服务器(该服务器命名为A)。所有的用户验证都通过此服务器验证,其他服务器对用户信息的获取,用户的身份确认,都要通过这个服务器来实现。<br> 2、在应用服务器(该服务器命名为B)的所有需要验证的地方判断用户信息是否已经验证,如果没有验证,则通过 IFRAME 在用页面放一个A服务器的验证页面,并传递一个A可以识别的标记参数,告诉A服务器是B服务器需要验证当前用户。<br> 3、A服务器获得B服务器的页面请求后,首先检查当前用户是否登陆,如果没有登陆,则停止验证,或者反馈一个尚未登陆的页面。<br> 4、如果A用户收到B服务器的也面请求后,发现当前用户已经登陆,则生成一个随机的长的字符串并在记录下该字符串、生成时间、对应的用户记录、B服务器的标记。然后通过自动跳转技术,访问B服务器上的一个用户信息验证页面,同时传递所生成的长字符串。(该页面由A从自身记录中获取,由事先录入);<br> 5、B服务器的验证页面收到到所传递的长字符串后,在服务器端访问A服务器的服务器端信息确认页面,同时传递所收到的长字符串以及服务器标识。<br> 6、A服务器的服务器端信息确认页面收到信息后,通过字符串与发出请求的服务器来验证信息的正确性:<br> (1)首先判断服务器IP是否属于该PASSPORT的服务服务器列表;<br> (2)通过字符串查询记录中是否有该字符串;<br> (3)通过请求服务器的IP与保留的服务器标记核对,看是否请求的IP地址是当前记录的服务器的;<br> (4)判断字符串的生成时间与当前时间比较,是否超时,超时的设置,在A服务器上设置;<br> (5)如果都核对无误,则返回对应的用户信息,否则反馈错误信息;<br> 7、B服务器受到A服务器的确认信息后,根据确认信息的内容,判断用户是否登陆成功,如果登陆成功,则给当前用户分配SESSION。如果不成功,则返回空白或者重复刚才的进程,重新验证(重新验证需要记录次数,当次数超过一定量,则无条件停止验证,避免死循环)</p> <p>Passport跨域认证解决方法 参考:<br> 服务器端可控JS跨域访问解决方法</p> <p>http://bbs.ad0.cn/viewthread.php?tid=302&extra=page%3D1</p> <p>SSO – Single Sign-On Enterprise Security for Web Applications</p> <p>http://bbs.ad0.cn/viewthread.php?tid=304&extra=page%3D1</p> <p>单点登录的简单实现</p> <p>http://bbs.ad0.cn/viewthread.php?tid=305&extra=page%3D1</p> <p>PHP实现WebServices和跨域自动登陆</p> <p>http://bbs.ad0.cn/viewthread.php?tid=307&extra=page%3D1</p> <p>Passport跨域认证解决方法</p> <p>http://bbs.ad0.cn/viewthread.php?tid=309&extra=page%3D1</p> <p>Web应用跨域访问解决方案</p> <p>http://bbs.ad0.cn/viewthread.php?tid=310&extra=page%3D1</p> <p>Flex或Flash的跨域访问解决方案</p> <p>http://bbs.ad0.cn/viewthread.php?tid=313&extra=page%3D1</p> <p>跨域访问新方案-PHPRPC</p> <p>http://bbs.ad0.cn/viewthread.php?tid=315&extra=page%3D1</p> <p>SSO-单点登录完全解决方案<br> —-最全的SSO解决方案,<br> AJAX跨域问题,IFrame跨域问题,Cookies跨域,session跨域问题,Js跨域问题,等常见跨域问题均有提及<br> Ajax跨域工具: Modello.ajax<br> —跨浏览器、跨域的Ajax工具</p> <p>跨域访问新解决方案(跨域调用新方案)- PHPRPC<br> PHPRPC – perfect high performance remote procedure call<br> PHPRPC 是一个轻型的、安全的、跨网际的、跨语言的、跨平台的、跨环境的、跨域的、支持复杂对象传输的、支持引用参数传递的、支持内容输出重定向的、支持分级错误处理的、支持会话的、面向服务的高性能远程过程调用协议。<br> 目前该协议的最新版本为 3.0。该版本目前已有以下几种语言的实现:</p> <p>ASP:提供 JScript 和 VBScript 两种语言的支持。<br> ActionScript:提供 ActionScript 2.0 和 ActionScript 3.0 两个版本的支持。<br> Java:支持 JDK 1.4 以上的所有版本,它还支持 Google Android 开发包。<br> JavaScript:提供两个版本的实现,一个使用纯 Javascript 实现,另一个需要调用一个 swf 文件,两个版本都支持跨域的远程过程调用,但是使用 swf 的版本不限制参数长度,并且有更好的安全控制机制。这两个版本已经通过完整测试的浏览器包括 IE 5+,Netscape 7+,Firefox,Mozilla,Opera,Safari,Epiphany,Camino 与 Konqueror。并且纯 JavaScript 版本还通过了 Pocket IE、Opera Mini、Opera Mobile、iPhone、Android 等手持设备浏览器的测试。<br> .NET:支持 .NET 框架下所有的语言(如 C#、VB.NET、VC.NET、Delphi.NET 等),并且支持目前所有版本的 .NET Framework 和 .NET Compact Framework,当然它也支持 Mono。<br> PHP:支持 PHP4 与 PHP5,同样支持正处于开发阶段的 PHP6。<br> Perl:目前该版本尚不成熟,有待完善。<br> 其中 ASP、.NET、Java 和 PHP 版本除了提供客户端实现外,还提供了 服务器端实现。</p> <p>PHPRPC 3.0下载:http://www.phprpc.org/download/phprpc_3.0.zip</p> <p>PHPRPC 3.0各版本: http://www.phprpc.org/zh_CN/download/<br> 搜索《跨域访问新方案-PHPRPC》相关主题: 远程调用 跨域调用 解决方案 跨域访问 PHPRPC PHPRPC 方案 访问</p> <p>==========================================================<br> php sso单点登录实现方案</p> <p>http://www.dayanmei.com/blog.php/ID_1021.htm</p> <p>由于已经现成有多个不同的应用,各个应用有自己的user数据,我拟定的做法是<br> 1. 共建一个user表,通过应用绑定用户跟user表的关系<br> 拷贝所有现有的用户和密码到新表,并验证密码的验证方式函数<br> 2. 一个配置文件中设置各个应用与user表之间传输加密解密协议<br> 3. 当一个用户登录时他首先携带当前的url地址或者是需要返回的url地址和通过加密协议加密后的字串提交到验证服务器,验证后返回加密后的状态和票据,其中可能包含过期时间产生时间等,<br> 如果成功,则同样的票据通过javascript src的方式提交给其他的应用,产生cookie或者session<br> 4. php sso单点登录实现方案文件示例<br> config.inc.php 公用密钥和验证函数库<br> ps-mm.cn域名下文件<br> a_setcookie.php (产生cookie 登录当前应用)<br> printcookie.php (测试打印cookie)<br> dayanmei.com 域名下文件<br> 验证服务器文件<br> b_setcookie.php<br> 内容:<br> config.inc.php<br> <?php<br> $key = ‘123456789′;<br> function authcode($string, $operation, $key = ”) {<br> $key = md5($key ? $key : $GLOBALS['auth_key']);<br> $key_length = strlen($key);<br> $string = $operation == ‘DECODE’ ? base64_decode($string) : substr(md5($string.$key), 0, 8).$string;<br> $string_length = strlen($string);<br> $rndkey = $box = array();<br> $result = ”;<br> for($i = 0; $i <= 255; $i++) {<br> $rndkey[$i] = ord($key[$i % $key_length]);<br> $box[$i] = $i;<br> }<br> for($j = $i = 0; $i < 256; $i++) {<br> $j = ($j + $box[$i] + $rndkey[$i]) % 256;<br> $tmp = $box[$i];<br> $box[$i] = $box[$j];<br> $box[$j] = $tmp;<br> }<br> for($a = $j = $i = 0; $i < $string_length; $i++) {<br> $a = ($a + 1) % 256;<br> $j = ($j + $box[$a]) % 256;<br> $tmp = $box[$a];<br> $box[$a] = $box[$j];<br> $box[$j] = $tmp;<br> $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));<br> }<br> if($operation == ‘DECODE’) {<br> if(substr($result, 0, <img alt="8)" src="https://simg.open-open.com/show/25c83ea511f206e88f214719dad9c88c.gif"> == substr(md5(substr($result, 8).$key), 0, 8)) {<br> return substr($result, 8);<br> } else {<br> return ”;<br> }<br> } else {<br> return str_replace(‘=’, ”, base64_encode($result));<br> }<br> }<br> //posts transaction data using libCurl<br> function libCurlPost($url,$data) {<br> //build post string<br> foreach($data as $i=>$v) {<br> $postdata.= $i . “=” . urlencode($v) . “&”;<br> }<br> $postdata.=”cmd=_notify-validate”;<br> $ch=curl_init();<br> curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);<br> curl_setopt($ch,CURLOPT_URL,$url);<br> curl_setopt($ch,CURLOPT_POST,1);<br> curl_setopt($ch,CURLOPT_POSTFIELDS,$postdata);<br> //Start ob to prevent curl_exec from displaying stuff.<br> ob_start();<br> curl_exec($ch);<br> //Get contents of output buffer<br> //$info=ob_get_contents();<br> curl_close($ch);<br> //End ob and erase contents.<br> ob_end_clean();<br> //return $info;<br> }<br> //posts transaction data using fsockopen.<br> function fsockPost($url,$data) {<br> //Parse url<br> $web=parse_url($url);<br> //build post string<br> foreach($data as $i=>$v) {<br> $postdata.= $i . “=” . urlencode($v) . “&”;<br> }<br> $postdata.=”cmd=_notify-validate”;<br> //Set the port number<br> if($web[scheme] == “https”) { $web[port]=”443″; $ssl=”ssl://”; } else { $web[port]=”80″; }<br> //Create paypal connection<br> $fp=@fsockopen($ssl . $web[host],$web[port],$errnum,$errstr,30);<br> //Error checking<br> if(!$fp) {<br> //echo “$errnum: $errstr”;<br> }else {<br> fputs($fp, “POST $web[path] HTTP/1.1\r\n”);<br> fputs($fp, “Host: $web[host]\r\n”);<br> fputs($fp, “Content-type: application/x-www-form-urlencoded\r\n”);<br> fputs($fp, “Content-length: “.strlen($postdata).”\r\n”);<br> fputs($fp, “Connection: close\r\n\r\n”);<br> fputs($fp, $postdata . “\r\n\r\n”);<br> //loop through the response from the server<br> while(!feof($fp)) {<br> $info[]=@fgets($fp, 1024);<br> }<br> //close fp – we are done with it<br> fclose($fp);<br> //break up results into a string<br> $info=implode(“,”,$info);<br> }<br> return $info;<br> }<br> ?><br> Pirntcookie.php<br> <?php<br> print $_COOKIE['test'];<br> ?><br> A_setcookie.php<br> <?php<br> header(‘P3P: CP=”CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV”‘);<br> include(‘config.inc.php’);<br> $string = explode(“\n”,authcode($_GET['string'],’DECODE’,$key));<br> setcookie(“test”, $string[1], time()+3600, “/”, “.ps-mm.cn”);<br> ?><br> B_setcookie.php<br> <script src=”http://www.ps-mm.cn/a_setcookie.php?string=f20Bq5QGXqSRKlpwuTfB”></script></p> <p> </p> <p> </p> <p>来自: <a href="/misc/goto?guid=4959673497229745897" rel="nofollow">http://blog.csdn.net/fangaoxin/article/details/6929415</a></p> <p> </p> <p> </p>