2008年7月20日星期日

浅谈Gecko关键部分之七安全及其实现

很长一段时间以来Firefox以安全、小巧、快捷著称,从而逐步从饱受不安全批评的IE中抢夺到部分用户的支持,在用户心中确立了Firefox比IE更安全的想法,其实浏览器的安全一直受到人们的广泛关注,但往往不能做到百分百的完美,似乎总有一些遗憾的地方,正所谓道高一尺魔高一丈。为了更深入的了解浏览器技术,安全正可谓不得不面对的问题,也许它比较的复杂,涉及面比较广,还是让我们从安全问题的出现、Gecko内核的安全策略及其主要实现路径等方面来学习研究,以便达到以一窥十的效果。

一、安全问题的出现
浏览器作为一个通往互联网的入口,其可以连接访问的网站成千上万,并且类型也缤纷多彩,正是这一点突出了浏览器功能强大、实用的特点,进而确立其在互联网应用中不可缺失的地位,但同时也带来了人们的疑虑,我们刚才访问的网站是否下载了病毒、是否破坏了操作系统、提交的数据如用户名密码是否泄漏、访问的历史记录是否遭到外部网站的截取等等。这些问题从浏览器出现的一刻起就受到浏览器开发者的关注,到目前为止,有些浏览器还是受到人们广泛的质疑。

其实困扰人们心中的浏览器安全问题往往可分为两类:
对用户本地私有数据的保护

私有数据往往包含两方面,一方面在于操作系统的文件是否遭到访问、读写等,其实一旦存在这类漏洞,其危害是特别大的,往往会导致整个操作系统的不安全,我们以前通过IE访问不良网站时,经常会遭遇到木马等病毒的骚扰,其实问题的出现正是由于病毒利用了activex组件等方面的漏洞,从而重新配置操作系统,并下载病毒文件等。另一方面在于保护用户保存的Cookie、历史访问记录,提交的表单数据是否遭到非法访问,在同一浏览中同时打开的不同页面是否能相互访问,共享数据等。

其实在浏览器设计之初就充分考虑到这些方面的问题,特别在javascript设计之初,因为浏览器能够执行外部网站的操作往往来源于javascript脚本,一旦能控制住浏览器为脚本提供的接口的安全性,浏览器的安全问题就得到架构上保证,再加上javascript本身是脚本语言,这样为任何一句脚本语言提供执行前的检查提供了可能。正是基于这样的出发点,javascript的实现是基于sanbox技术的,脚本语言的执行是在一个安全的上下文中进行的,它所造成的危害是可控的如从理论上讲,javascript是不可以访问操作系统文件的,是不可以上传不由用户指定的任意文件的。当然其中很多相关的安全细则可参考相关js手册,其实现是由内核来提供保证的。

对用户提交给网站数据的保护
浏览器往往通过http协议来与网站进行数据交互,由于http协议属于应用层协议,交互的数据对网络层来讲是透明的,也是不安全的,作为一个能广泛使用的应用程序,为了满洲需对提供的银行帐户与密码进行加密等需求,浏览器必须提供一些数据加密措施来保证数据交互的安全。基于这一点及广泛标准的支持,Gecko内核采用了PKI开源应用模块(相对来说蛮独立)来保证数据加密的要求如对PKCS #5, PKCS #7, PKCS #11, PKCS #12, S/MIME, TLS, SSL v2 and v3, X.509 v3 certificates等方面的支持,而没有使用目前很多项目都采用的OpenSSL来对SSL的支持,不过SSL作为一个标准,无论采取OpenSSL还是PKI,只不过是实现上的不同而已。

其中人们经常听说的反钓鱼技术,往往与此有点关联。
网络钓鱼 (phishing)是国际通用的新字,取phreak(偷接电话线的人)的前两个字母ph取代fishing(钓鱼)的f,是以社会工程学(也就是骗术)结合电脑科技的新犯罪手法。

网络钓鱼的目的是骗取受害人的网站上的帐号密码(网络银行或线上游戏)、信用卡资料以及个人资料,进行例如线上转帐、偷取游戏虚拟宝物、窥伺别人的email以及盗刷银行卡等违法行为。

钓鱼正以一种新的犯罪形式侵犯,在不断侵犯普通网民的合法利益,具体表现在伪装“网络银行”窃取用户的银行卡卡号和密码,转走用户在银行的存款;伪装成网 络游戏的官方网站窃取用户的网游帐号,转走用户在游戏里面的虚拟货币或者虚拟装备; 伪装成送QQ币的网站让用户输入QQ号和密码进而窃取QQ号……

其中Firefox应该是目前提供反钓鱼技术最好的浏览器,它不仅提供反盗取密码等网站,还提供反不安全、非法及含有黄色内容的网站。
其实现机制往往结合nsIContentPolicy接口及维护后台不安全网站列表来共同实现。

如须具体了解数据加密的内容,可更加深入的了解PKI OpenSource等方面的知识,这次主要学习研究对本地私有数据安全方面的内容。

二、Gecko内核的安全策略
为了保证数据的提交与行为的安全执行,Gecko内核中提供两种安全策略,Same-Origin Policy和Security Zones and Signed Scripts。

其中Same-Origin Policy的主要含义在于一段脚本只能访问具有同一来源的window及document的内容,同一来源包括同一主机、同一端口、同一协议,同时为了对扩展域名的支持,同一来源也指具有同一domain的不同window及document

而Security Zones and Signed Scripts指的是为了给一段脚本更高的访问权限,需要由用户确认后来授权该脚本可以拥有更高的权限。其实现的方式有通过SignTool及安全Jar的方式来授权、提示用户由用户来确认的方式来授权。其中前一种相当复杂,普通用户使用较少,而后一种方式应用较多,并且可以由用户自己来配置一些对象的属性、方法的访问权限或自定义一些域名浏览器访问权限,下面示例一些权限设置。
user_pref("capability.policy.default.Window.open", "noAccess");

user_pref("capability.policy.policynames", "strict");
user_pref("capability.policy.strict.sites", "http://www.evil.org http://www.annoying.com"); user_pref("capability.policy.strict.Window.alert", "noAccess");
user_pref("capability.policy.strict.Window.confirm", "noAccess");
user_pref("capability.policy.strict.Window.prompt", "noAccess");

user_pref("capability.principal.codebase.p2.granted", "UniversalXPConnect");
user_pref("capability.principal.codebase.p2.id", "http://192.168.1.200");
user_pref("capability.principal.codebase.p2.subjectName", "");


一段脚本可拥有的浏览器访问权限包括UniversalBrowserRead、UniversalBrowserWrite UniversalXPConnect、UniversalPreferencesRead、UniversalPreferencesWrite CapabilityPreferencesAccess、UniversalFileRead等,它们可以通过netscape.security.PrivilegeManager.enablePrivilege("UniversalPreferencesRead");等方式来设置权限,如果用户的signed.applets.codebase_principal_support配置选项设为true,在设置权限时会提示用户是否设置该codebase权限。

三、安全主要实现路径
首先由javascript SpiderMonkey提供了一组安全方面的接口,以供脚本安全的检查,至于具体的安全规则则由xpconnect及securitymanager来实现,主要接口有JSPrincials、JS_CheckAccess、
JSObjectOps.checkAccess、JSClass.checkAccess、JS_SetPrincipalsTranscoder等;

然后由nsScriptSecurityManager来管理维护其提供的nsPricipal实例及相关的安全检查,其中在其初始化时完成如下主要操作:

nsresult nsScriptSecurityManager::Init()
{
nsresult rv = InitPrefs();//将用户自定义的pricipal组织起来
NS_ENSURE_SUCCESS(rv, rv);
。。。。。。。。。。。。。。。。
// Create our system principal singleton
nsRefPtr system = new nsSystemPrincipal();
NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY);
rv = system->Init();
NS_ENSURE_SUCCESS(rv, rv);

mSystemPrincipal = system;
。。。。。。。。。。。。。。。
//-- Register security check callback in the JS engine
// Currently this is used to control access to function.caller
nsCOMPtr runtimeService =
do_GetService("@mozilla.org/js/xpc/RuntimeService;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);

rv = runtimeService->GetRuntime(&sRuntime);
NS_ENSURE_SUCCESS(rv, rv);

//CheckObjectAccess成为安全检查的主要入口点
JS_SetCheckObjectAccessCallback(sRuntime, CheckObjectAccess);

sXPConnect->GetXPCWrappedNativeJSClassInfo(&sXPCWrappedNativeJSClass,
&sXPCWrappedNativeGetObjOps1,
&sXPCWrappedNativeGetObjOps2);

return NS_OK;
}

在实现的过程中会提供一些nsPrincipal实例如nsNullPrincipal、nsSystemPrincipal来表示不同的安全规则,同时每一个nsPricipal实例都包含一个JSPricipals接口实例,其内容可由JS_SetPrincipalsTranscoder来根据不同情况来设定,这样可以为不同的JSContext、JSClass、JSObject、JSFunction设置对应的JSPricipals,由它可以获得nsPrincipal实例,以了解真正的安全规则。

其中由SpiderMonkey JS Engineer内部或Xpconnect、nsScriptSecurityManager等外部在需要实施安全规则检查的地方如检查xpcom组件接口参数发起JS_CheckAccess的执行,其中会调用上面提到的回调函数CheckObjectAccess,以触发nsSecurityManager来统一对安全的检查,起到sanbox的作用。具体的nsPricipal及nsSecurityManager的管理可参考\mozilla\caps\src\nsPricipal.cpp及nsScriptSecurityManger.cpp等,至于如何为JS对象设置一些JSPricipals则需要更深入对函数JS_SetPrincipalsTranscoder的调用与实现作一些了解。

四、参考资源
Mozilla Security Review and Best Practices Guide
The Same Origin Policy
Signed Scripts in Mozilla
Configurable Security Policies
JSAPI User Guide
Open Source PKI Projects



没有评论: