APP下载

基于SSL证书认证中间件的安全性分析

2014-04-25鲜乾坤雷建平

关键词:中间件应用程序证书

何 旭,鲜乾坤,雷建平

(1.达州职业技术学院,四川 达州 635001;2.四川理工学院计算机学院,四川 自贡 643000;3.61902部队,四川 宜宾 644000)

引 言

Web浏览器的SSL已经成为网络安全的事实标准,SSL主要目的是针对中间件攻击提供端到端的安全保障,即使网络受到像DNS入侵或者路由器被控制等这样的威胁,SSL也能够保证客户机与服务器之间通信的机密性、真实性、完整性[1-2]。

认证服务器是SSL连接建立的关键部分,其公钥证书身份验证发生于SSL握手阶段。同时,为了保证SSL连接是安全的,客户端必须确认证书是有效证书,即既没有过期也没有被撤销,用以检查证书名称、客户端连接的匹配性[3-4]。

Web浏览器对SSL功能的实现可以通过加入补丁保证安全性,这样许多与SSL相关的浏览器漏洞就可以得到修复[5-6]。然而,SSL也广泛用于非浏览器软件,如基于云计算虚拟基础设施的远程管理以及发送本地数据到云存储,以及Android、iOS等移动应用程序的验证服务。这些程序通常不实现SSL本身,主要依靠OpenSSL、JSSE与CryptoAPI等SSL库以及更高层次数据传输库作为SSL封闭,在基于Web服务软件用额外抽象层引入Web服务中间件。

入侵者可能控制路由器、交换机、无线AP或DNS,也可以控制一个或多个拥有SSL证书的服务器。当SSL客户机试图连接到一台合法服务器时,入侵者可以通过DNS挟持诱导服务器,并欺骗用户连接到一台入侵者控制的服务器。

1 SSL证书认证机制

SSL握手协议是一个更高层的客户端SSL协议,该协议是用来协商会话的安全属性,握手消息提供给SSL记录层,并封装在一个或多个SSLPlaintext数据结构内,用以处理与传输当前活动会话状态。SSL连接开始于客户端和服务器之间的握手,这样SSL客户端的“确认服务器认证”容易作为攻击目标。SSL握手协议由RFC6101[7]给出了完整描述,其握手过程如图1所示。

图1 SSL握手协议描述

信任链验证。每个X.509证书有一个“issuer”属性,其中包含CA的名称,每台SSL客户端配置可信根CA证书列表。除自己的证书外,还有该服务器发送的发行CA认证。如果签发的CA不是根CA,服务器还发送一个更高级别通向根CA的证书列表。客户端试图建立一个从底部服务器证书开始的链,链中每个证书必须立即由上级CA签署,根CA必须是客户信任的CA之一,客户验证证书没有过期、中间CA认证以及设置有“Basic Constraints”字段。完整的X.509证书认证算法由 RFC5280[3]与 RFC2818[4]给出了描述。

主机验证。信任链建立后,客户端必须验证服务器的身份。RFC2818[4]建议使用“SubjectAltNames”作为服务器标识符主要来源以及支持“Common Name”向后兼容,但大多数软件是先检查“Common Name”。构建服务器标识列表后,客户端尝试匹配所有符合DNS域名的被请求服务器标识符。如果客户端在服务器标识符列表中找到一条精确匹配,就通过简单字符串比较进行验证,客户端也可以查找一个匹配规则复杂的通配符名字标识符的列表[4,8]。

证书撤销。OpenSSL的一些 SSL库实现证书撤销[9],但要求应用程序提供证书撤销列表(CRL)。虽然JSSE库要求应用程序检查自身CRL的有效性,但大多数应用程序不用检查,如有些SSL库(Python的SSL)不公开CRL的检查方法。

X.509扩展。一些X.509证书扩展包含关键安全信息,如key useage(CA允许使用该秘钥签署证书)、name constraints(限制子CA能够签署的认证)以及RFC2527[10]描述的证书策略。虽然CA可以分配不同的信任级别给子CA,但应用程序必须提供利用这些信息的策略,实际上这些扩展在很大程度上可以被忽略,即或是目前的OpenSSL也没有正确验证名字约束,而cURL甚至没有接口用于指定应用程序证书策略。

2 SSL抽象化安全分析

根据需求,应用程序可以插入到不同层次抽象的SSL内,但在最低层次有多种使用不同属性、许可、硬件请求来实现通用 SSL,如 OpenSSL、JSSE、CryptoAPI等。因此,为了避免自己解析HTTP,所以使用SSL的HTTP应用程序通常不直接使用,而使用HTTPS在内部使用SSL库,SOAP或基于REST的Web服务应用程序在其上层使用额外中间件 HTTPS或 Web Socket,如图2所示。

图2 使用SSL的协议栈

2.1 SSL库

OpenSSL。OpenSSL只提供信任链验证,而应用程序必须支持自身主机验证。不同应用层协议(HTTPS,LDAP)有不同有效主机组成限制和证书列表匹配要求,因此主机验证必须通过应用程序自身管理或数据传输层封装。OpenSSL通过提供返回函数或修改配置允许应用程序定制信任链验证[11],如配置“验证深度(verify depth)”和“验证模式(verify mode)”(图3)。

使用OpenSSL的程序可以通过调用SSL_connect函数执行SSL握手。证书验证错误信息通过SSL_connect函数返回值提供,而其他错误由SSL_connect函数设置内部verify result标识,应用程序必须调用SSL_get_verify_result函数以检查是否发生此类任何错误[12]。

图3 使用缺省信任链验证SSL连接设置的OpenSSL API图

JSSE。Java安全套接字扩展(JSSE)提供大量接口给Java应用程序(包括Android移动应用程序)建立SSL连接。低层通过SSLSocketFactory创建的SSL客户端API可能不执行主机验证。

下面的代码段来自于X.509的TrustManagerImpl.checkIdentity。

private void checkIdentity(String hostname,

X509Certificate cert,String algorithm)

throws CertificateException{

if(algorithm!=null&&algorithm.length()!=0){

....

if(algorithm.equalsIgnoreCase("HTTPS")){

HostnameChecker. getInstance(HostnameChecker.TYPE_TLS).match(hostname,cert);

}else if(algorithm.equalsIgnoreCase

("LDAP")){

HostnameChecker. getInstance(HostnameChecker.TYPE_LDAP).match(hostname,cert);

}else{

throw new CertificateException("Unknown

identification algorithm:"+algorithm);

}

}

}

上述代码段的功能是实现对主机名与认证的确认。如果algorithm设置为HTTPS或 LDAP,checkIdentity方法就抛出一个异常,其不同于OpenSSL的返回值,即使验证失败也认为应用程序会检查该值。在HttpsClient和HttpsURLConnection等JSSE应用程序中,当创建SSL客户端时就会调用SetHostnameVerification方法并设置为HTTPS,其结果是调用HostnameChecker和验证证书。

如果客户端字段是NULL或空串,checkIdentitysilently跳过主机验证且不抛出异常。该作法是为了适应基于证书协议实现而重用JSSE的默认值HTTPS或LDAP以验证信任链。Java7.3的证书验证代码与Java6不同,如果字段是NULL或空串,checkIdentity根本就不调用。

private void checkTrusted(X509Certificate[]chain,

String authType,Socket socket,boolean isClient)

throws CertificateException{

...

String identityAlg=sslSocket.getSSLParameters().

getEndpointIdentificationAlgorithm();

if(identityAlg!=null&&identityAlg.length!=0){

String hostname=session.getPeerHost();

checkIdentity(hostname,chain[0],identityAlg);

}

}

上述代码段实现对信任链的验证功能,验证链路中各节点主机间的信任关系。在SSL客户端使用SSLSocketFactory,如果该字段为空JSSE就不执行主机验证,主机验证工作就由运行在JSSE上层的软件完成,该功能在JSSE参考指南有警告说明。

在发送任何数据前使用SSLSockets/SSLEngines应该检查各节点证书,因为SSLSocket和SSLEngine类不自动验证与URL匹配的域名验证,如果不进行主机验证应用程序,这样就可以利用 URL欺骗。Java软件使用SSLSocketFactory创建SSL客户端但不执行主机验证,说明开发人员并没意识到该特性,而JSSE接口执行主机验证也增加了其混乱性。

2.2 数据运输层的安全机制

实际上大多数应用程序依赖数据运输层建立HTTPS连接,这些在内部使用SSL库架构通常是不透明的应用程序。

Apache HttpClient。Apache HttpClient是基于 JDK的客户端HTTP Java库。Apache HttpClient广泛用于Web服务中间件,是因为本地化JDK不支持SOAP Web服务,且在发送HTTP POST请求等功能时,Apache Http-Client比JDK提供了更好性能。Apache HttpClient使用JSSE的SSLSocketFactory建立SSL连接,即Apache Http客户端必须执行自己的主机验证,这样对于基于旧版本的HttpClient不验证主机就会导致很多漏洞。Apache HttpClient使用HttpHost数据结构描述 HTTP连接,而HttpHost并没有任何内部一致性检查,如允许连接到443端口。

cURL。cURL是一个从远程服务器获取数据的工具和库。从7.10版本开始,cURL默认验证SSL证书。内部cURL使用OpenSSL验证信任链和主机,其功能由参数 CURLOPT_SSL_VERIFYPEER(默认值 true)和CURLOPT_SSL_VERIFYHOST(默认值2)控制,VERIFYPEER参数是布尔类型,而VERIFYHOST参数是整数。开发人员经常误解这些参数,而且将CURLOPT_SSL_VERIFYHOST设置为TRUE,从而改变其值为1,这样如果意外禁用主机验证就会带来不安全的后果。

PHP。PHP提供多种方法建立SSL连接,打开远程服务器套接字的fsockopen能够通过在URL中加入“SSL://”连接到SSL服务器。尽管fsockopen不执行任何证书检查,PHP应用程序开发人员通常用它来建立SSL连接。PHP也提供cURL绑定,使用cURL默认设置建立SSL连接以适应证书验证,开发人员可能设置cURL不正确选项改变默认值,从而破坏证书验证。

3 非浏览器软件SSL的分析

云客户端API。云端API是连接云端与客户端的桥梁,它包括面向各不同协议客户端的API和面向第三方的API。前者的作用是云端与客户端之间的交互,使用RTMP或RTMPE协议传输;后者允许定制特定函数输出给第三方,使用RTMP或RTMPE传输,或通过本地的PHP中转为HTTP传输。对于第三方云计算平台的运行在客户端SDK,可以通过第三方软件传送用户数据到基于云的存储、管理用户基于云的计算以及访问其他云服务。如Amazon在Java、PHP、Python和Perl中提供的EC2 API工具,以及Apache提供的独立库访问多个云的Libcloud。

Web services中间件。许多程序依赖于Web services。Web services是一软件系统,用来支持网络主机间的互操作性,其服务由一个接口描述计算机可读的XML格式文档。不同系统提供不同具体实现接口,异构系统间通过发送和接收信息实现服务的互操作。

使用基于XML的SOAP或REST的Web services发送与接收消息。从客户端软件的角度来讲,Web services可以被认为是提供远程过程调用RPC接口,而SOAP或REST中间件是RPC调用参数的封装和解封。

Web service通过使用SOAP中间件与现有Java软件进行交互。同样地,如果一个Android应用程序需要实时发送通知,它可以使用客户端库连接到基于REST的Pusher服务。这些中间件框架负责发送Web service信息到网络,如果连接必须是安全的,中间件通常使用SSL,而不是现在的SSL连接管理数据传输库代替。

4 Apache HttpClient的SSL API安全性应用分析

2007年发布并广泛使用的Apache HttpClient 3.1版本与较早期的版本一样,使用JSSE的SSLSocketFactory而不执行自身主机验证来建立SSL连接。这样Apache HttpClient 3.*接受任何具有有效信任链的证书,而不管其名字。

HttpClient主机验证的缺陷在4.0版得到修正,在4.2.1版本中,有其自身的主机验证和指派JSSE进行信任链验证。这样依靠SSL连接建立HttpClient实现对应用程序的安全性有较少影响。HttpClient的使用通常隐藏内部Web services中间件,从而跳过主机关于SSL证书认证。

值得注意的是,如果用户将自定义主机验证代码添加到HttpClient 4.*是错误的,并且将拒绝有效证书。下面的代码来自HttpClient 4.2.1:

String parts[]=cn.split("\.");

boolean doWildcard=parts.length > =3 &&

parts[0].endsWith("*")&&

acceptableCountryWildcard(cn)&&

!isIPAddress(host);

if(doWildcard){

if(parts[0].length()>1){

String prefix=parts[0].substring(0,parts.length-2);

String suffix=cn.substring(parts[0].length());

String hostSuffix=hostName.substring

(prefix.length());

match=hostName.startsWith(prefix)

&& hostSuffix.endsWith(suffix);

}else{

match=hostName.endsWith(cn.substring(1));

}

if(match&& strictWithSubDomains){

match=countDots(hostName)==countDots(cn);

}

}else{

match=hostName.equals(cn);

}

该代码段具有计算来自CN的主机名验证、通配符使用处理、CN与主机通配符忽略处理功能。其方法是计算参数parts的数字部分减去2的前缀长度,域名第一部分有效性什么也不操作而其就不具有逻辑性。如,如果证书名是 a*.<b>.<b>.com,它将拒绝 ail.<b>.<b>.com。而且最初的补丁及其衍生代码在解析IPv4地址通用表达式中有一个小缺陷,使其接受从0开始的IP地址,但这并不会立即导致安全漏洞。

5 结论

通过对具有代表性的中间件应用程序使用SSL用于安全连接的情况分析,特别对中间件库使用SSL作为多层软件协议栈的一部分功能分析,发现程序在具有潜在不安全的公用网络中传输极其敏感的数据时,非常重要的一点就是必须正确使用SSL。

同时通过对SSL在应用程序软件设计中的使用,详细说明了依赖标准SSL库的应用程序(如JSSE、OpenSSL等)执行SSL证书认证可能存在的不安全因素,这些不安全性在有些软件中是随处可见的,如FPS、PayPal、EC2以及其他客户端远程管理云存储和云基础设施等。这些特点对中间件攻击来讲,SSL连接是没有安全性的。

另外,对于一些宣称是更加安全的SSL策略,通过分析发现,可以通过开发代码分析工具发现SSL连接建立逻辑错误问题。对于这类情况,可以通过形式验证技术设计和编程,支持自动检查应用程序是否正确使用SSL库,而不误解关键选项和参数的定义,以此来设计更好的API用于SSL或其他安全的网络协议,从而解决其不安全隐患等。

[1]舒剑.一种无证书认证密钥协商协议的分析与改进[J].计算机应用研究,2012,29(1):294-296.

[2]张延红,陈明.标准模型下强安全的无证书认证密钥协商协议[J].四川大学学报:工程科学版,2013,45(1):125-132.

[3] HTTP over TLS[EB/OL].(2000-05-01)[2014-03-10].http://www.ietf.org/rfc/rfc2818.txt.

[4]Internet X.509 public key infrastructure certificate and certificate revocation list(CRL)profile[EB/OL].(2008-05-01)[2014-03-10].http://tools.ietf.org/html/rfc5280.

[5]何 旭.一种可扩展Web模型安全机制[J].计算机系统应用,2012,21(8):89-93.

[6]何旭.隐私模式浏览器的安全性分析[J].西华大学学报:自然科学版,2012,31(3):17-22.

[7] The Secure Sockets Layer(SSL)protocol version 3.0[EB/OL].(2011-08-01)[2014-03-11].http://tools.ietf.org/html/rfc6101.

[8] Representation and verification of domain-based application service identity within Internet public key infrastructure using X.509(PKIX)certificates in the context of Transport Layer Security(TLS)[EB/OL].(2011-03-01)[2014-03-11].http://tools.ietf.org/html/rfc6125.

[9] https should check CN of x509 cert[EB/OL].(2007-04-22)[2014-03-12].https://issues.apache.org/jira/browse/HTTPCLIENT-613.

[10] Internet X.509 public key infrastructure certificate policy and certification practices framework[EB/OL].(1999-03-01)[2014-03-11].http://www.ietf.org/rfc/rfc2527.txt.

[11] Viega J,Messier M.Secure programming cookbook for C and C++[M].California:O'Reilly Media,2003.

[12] Moxie M.IE SSL vulnerability[EB/OL].(2002-05-08)[2014-03-12].http://www.thoughtcrime.org/ie-ssl-chain.txt.

猜你喜欢

中间件应用程序证书
WJCI 收录证书
CSCD收录证书
收录证书
收录证书
删除Win10中自带的应用程序
谷歌禁止加密货币应用程序
RFID中间件技术及其应用研究
基于Android 平台的OSGi 架构中间件的研究与应用
中间件在高速公路领域的应用
一种支持智能环境构建的中间件