-
-
[转帖]通信安全:IOS客户端证书校验方法
-
发表于: 2017-11-29 09:40 6124
-
随着移动互联网的发展,互联网应用也在与日俱增,传统的金融行业,如银行的手机银行业务,现在热门的互联网金融企业,其移动应用都在不断的更新,同时,移动客户端的安全性也受到了前所未有的威胁,如盗版app,SQL注入,任意用户密码重置等漏洞,但这些漏洞的进一步利用很多情况下都依赖于中间人攻击,也就是客户端与服务端进行通信时未采用安全的https方式进行通信,而是采用不安全的http方式进行通信。本文就https基于SSL安全传输中相关问题进行了探索研究,以便在以后的客户端安全测试当中有一定的帮助。
由于移动互联网发展起始时间比较晚,开发人员也是近几年才发展起来,所以对于技术的水平也参差不齐。很多开发人员在开发初期都进行了比较安全的设计,但是在实现的时候没有很好的发挥其功能,特别是威胁比较大的SSL证书校验。有报道称,在2013年抽样对国内的手机银行客户端进行了SSL证书的安全测试,发现90%的客户端都没有很好的发挥了SSL证书校验的功能。
本文就当前IOS客户端SSL证书校验存在的问题做了阐述和分析,以帮助安全工程服务人员更好的测试ssl证书的安全性。
说到HTTPS通信,首先要说明一下HTTPS的通信原理。HTTPS是基于安全目的的Http通道,其安全基础由SSL层来保证。最初由netscape公司研发,主要提供了通讯双方的身份认证和加密通信方法。现在广泛应用于互联网上安全敏感通讯。
下面为IOS移动客户端其通信过程和证书校验过程可以用如下图过程展示:
第1步:IOS客户端发送一个连接请求给服务器;服务器将自己的证书(包含服务器公钥S_PuKey)、对称加密算法种类及其他相关信息返回客户端。
第2步:客户端检查服务器传送到CA证书是否由自己信赖的CA中心签发。若是,执行4步;否则,给客户提示连接错误或者拒绝连接。
第3步:客户端比较证书里的信息,如证书有效期、服务器域名和公钥S_PK,与服务器传回的信息是否一致,如果一致,则浏览器完成对服务器的身份认证。
第4步:服务器要求客户端发送客户端证书(包含客户端公钥C_PuKey)、支持的对称加密方案及其他相关信息。收到后,服务器进行相同的身份认证,若没有通过验证,则拒绝连接;
第5步:服务器根据客户端发送到密码种类,选择一种加密程度最高的方案,用客户端公钥C_PuKey加密后通知到客户端。
第6步:客户端通过私钥C_PrKey解密后,得知服务器选择的加密方案,并选择一个通话密钥key,接着用服务器公钥S_PuKey加密后发送给服务器;
第7步:服务器接收到客户端传送到消息,用私钥S_PrKey解密,获得通话密钥key。
第8步:接下来的数据传输都使用该对称密钥key进行加密。
由上述过程可以看到,要达到ssl安全通信,服务端和客户端都必有含有有效公私钥证书。
针对当前的市面上的IOS客户端,大多数客户端都采用http的方式进行通信。http通信方式是一种不安全的应用层通信方式,极易遭到中间人攻击。目前市面上的移动app主要有http方式和https方式进行通信,这里不再讨论http通信的优缺点,只讨论https通信方式上遇到的问题和安全加固建议。
缺陷描述:
无ssl证书校验是指虽然客户端与服务端的通信采用https加密通讯,但对ssl证书信任无任何校验,SSL证书形同虚设,无论服务器提供哪一种SSL证书指纹信息,客户端与服务端都可以正常通信,目前市场上80%的APP都没有很好的发挥SSL证书校验功能,甚至很大一部分APP都直接采用没有任何安全校验的http方式,这种客户端很明显的缺陷就是可以对app进行中间人攻击。
缺陷分析:
无证书校验最简单的黑河测试方式是对IOS设备做代理测试(IOS此时未越狱/不进行任何安装证书操作),当我们能抓取到https通信内容时,则证明此app与服务端间的通信未对ssl证书进行校验或者此app直接走http协议进行通信,如下图所示:
查看客户端代码,发现对ssl证书的校验没有开启:
//*配置服务端是否为SSL
#if defined (MODEL_RELEASE)
#define SERVER_SSL YES
#elif defined (MODEL_QUASIPRODUCTION)
#define SERVER_SSL YES
#else
#define SERVER_SSL NO
#endif
//#define SERVER_CHECKSSL YES//校验ssl证书
#define SERVER_CHECKSSL NO //不校验ssl证书
//省略部分代码
NSMutableString *urlString = [NSMutableString stringWithFormat:@”%@://%@”, useSSL ? @”https” : @”http”, self.hostName];
if(self.portNumber != 0)
[urlString appendFormat:@”:%d”, self.portNumber];
if(self.apiPath)
[urlString appendFormat:@”/%@”, self.apiPath];
if(![path isEqualToString:@”/”]) { // fetch for root?
if(path.length > 0 && [path characterAtIndex:0] == ‘/’) // if user passes /, don’t prefix a slash
[urlString appendFormat:@”%@”, path];
else if (path != nil)
[urlString appendFormat:@”/%@”, path];
}
return [self operationWithURLString:urlString params:body httpMethod:method];
}
//省略部分代码
NSMutableDictionary *webInfo = [[NSMutableDictionary alloc]initWithObjectsAndKeys:
[NSString stringWithFormat:@”%ld”,(long)completedOperation.HTTPStatusCode],@”httpStatus”,
completedOperation.responseString,@”WebData”,
nil];
onSuccessBlock([completedOp
以上代码可以说明客户端并没有对ssl证书做信任校验。
安全改进:
根据OWASP官方给出的对于IOS客户端,可以通过以下代码实现SSL证书信任操作:
{
[m_fetchedLabel setText:@””];
NSString* requestString = @”https://www.random.org/integers/?
num=16&min=0&max=255&col=16&base=16&format=plain&rnd=new”;
NSURL* requestUrl = [NSURL URLWithString:requestString];
ASSERT(nil!= requestUrl);
if(!(nil!= requestUrl))
{
[self displayError:@”Failed to create requestString.”];
return;
}
NSURLRequest* request = [NSURLRequest requestWithURL:requestUrl
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:10.0f];
ASSERT(nil!= request);
if(!(nil!= request))
{
[self displayError:@”Failed to create request.”];
return;
}
// Note that the delegate for the NSURLConnection is self, so delegate methods must be defined in this
file
NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
ASSERT(nil!= connection);
if(!(nil!= connection))
{
[self displayError:@”Failed to create connection.”];
return;
}
self.m_fetchedData = [[NSMutableString string] retain];
ASSERT(nil!= m_fetchedData);
}
-(BOOL)connection:(NSURLConnection*)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace
*)space
{
return [[space authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust];
}
– (void)connection:(NSURLConnection*)connection didReceiveAuthenticationChallenge:
(NSURLAuthenticationChallenge*)challenge
{
if ([[[challenge protectionSpace] authenticationMethod] isEqualToString:
NSURLAuthenticationMethodServerTrust])
{
do
{
SecTrustRef serverTrust= [[challenge protectionSpace] serverTrust];
ASSERT(nil!= serverTrust);
if(!(nil!= serverTrust)) break; /* failed */
OSStatus status= SecTrustEvaluate(serverTrust, NULL);
ASSERT(errSecSuccess== status);
if(!(errSecSuccess== status)) break; /* failed */
SecCertificateRef serverCertificate= SecTrustGetCertificateAtIndex(serverTrust, 0);
ASSERT(nil!= serverTrust);
if(!(nil!= serverTrust)) break; /* failed */
CFDataRef serverCertificateData= SecCertificateCopyData(serverCertificate);
ASSERT(nil!= serverCertificateData);
if(!(nil!= serverCertificateData)) break; /* failed */
[(id)serverCertificateData autorelease];
const UInt8* const data= CFDataGetBytePtr(serverCertificateData);
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)