IE 在默认情况下有很多的安全限制,比如跨框架跨域访问浏览器页面。对于程序员来说,经常遇到的问题就是通过调用IWebBrowser::get_Document时返回访问拒绝的错误,使用脚本语言也会收到有关权限的提示。
经过一段时间摸索,可以简单分析一下这种限制的原理。
首先,MS把浏览器对象(IWebBrowser2)划分成可信和非可信的两类。对于非可信的浏览器对象,访问Document属性是禁止的。到底哪些浏览器对象是非可信的呢?
1、非当前站点传出的浏览器对象访问当前站点的文档是不可信的。IObjectWithSite中传递的浏览器对象仅仅针对当前站点有效,如果访问其它浏览器对象中的内容将受限制。每个浏览器对象都有安全区域属性和域属性,只有在安全区域和域完全相同时才能越界访问。
2、外部通过宿主窗口直接获得的浏览器对象是不可信的。就像你从另一个IE进程中的浏览器窗口获得了浏览器对象,也无法访问浏览器里的文档。
是不是就没办法绕过安全限制呢?答案是否定的。IE提供了一种机制获得可信的浏览器对象,这种机制的前提是你需要在一个可信的浏览器对象中,即能够获得这个浏览器对象中的文档,那么你能获取这个文档所包含的所有子浏览器对象,方法是通过文档得到OleContainer,再通过容器来枚举所有的子对象,所得到的浏览器对象将同样是可信的,即使这些子浏览器对象的安全区域或域跟你所属的浏览器对象不同。但是反过来就不行,任何可信的浏览器对象也无法得到包容它自身的可信的父浏览器对象。
说到这里还没完,上面所说的方法仅仅适用于C++开发者,脚本语言开发者是绕不过去的。这是为什么呢?
原因在于除了上面的限制外,IE安全机制对可信浏览器对象的调用方式也进行了特别的限制,那就是只能通过虚表访问,不能通过分发接口访问。因为IWebBrowser实现了IDispatch,当跨域或者跨安全区域调用浏览器对象的Document属性时,Invoke调用受到禁止,但是虚表调用不受禁止,意思就是你能通过IWebBrowser2::get_Document得到想要的结果,但是通过IDispatch::Invoke将得不到正确的结果。在脚本语言里没有IWebBrowser2对象,有的只是IDispatch对象,所以脚本语言永远也无法越界得到浏览器的文档内容。当然相同安全区域和相同域的脚本越界访问还是允许的。
写得有点乱,算是一个笔记吧。