HTTPS 进阶

参考

一、中间人攻击

  概念:攻击者插入到原本直接通信的双方,让双方以为还在直接跟对方通讯,但是实际上双方的通信对方已经变成中间人,信息已经被中间人获取或篡改。

 

  HTTPS 的攻击分为两类:SSL 连接建立前的攻击;HTTPS 传输过程的攻击。

  • 0x00: SSL 证书欺骗攻击:将客户端段的访问重定向到攻击的机器(使用伪造证书),而攻击者机器在跟服务器连接。

 

    • 攻击工具:SSLSniff (伪造证书实现钓鱼攻击)
    • 防范措施:

      1)app 直接调用系统 API 创建的 HTTPS 连接一般不会受影响。只使用默认的系统校验,只要系统之前没有信任相关的伪造证书,校验就直接失败,不会 SSL握手成功;

      2)使用 webView 浏览网页,需要在 UIWebView 中加入较强的授权验证,禁止用户在校验失败的情况下继续访问。(特别是自己制作的证书,需要按照这篇文章的校验)

#import "HTTPSWebViewController.h"

@interface HTTPSWebViewController () <UIWebViewDelegate, NSURLConnectionDataDelegate> {
    NSURLRequest *aRequest;
    BOOL authenticated;
}

@property(nonatomic, strong) IBOutlet UIWebView *webView;

@end

@implementation HTTPSWebViewController

- (void)viewDidLoad{
    [super viewDidLoad];
    
    NSURL *url = [NSURL URLWithString:@"https://google.com"];
    NSURLRequest *requestURL = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:requestURL];
}

#pragma mark - UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    BOOL result = authenticated;
    if (!authenticated) {
        aRequest = request;
        NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
        [urlConnection start];
    }
    return result;
}

#pragma mark - NSURLConnectionDataDelegate
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    SecTrustRef trust = challenge.protectionSpace.serverTrust;
    SecTrustResultType result;
    
    OSStatus status = SecTrustEvaluate(trust, &result);
    if ((status == errSecSuccess) &&
        ((result == kSecTrustResultProceed) ||
         (result == kSecTrustResultUnspecified))) {
            
            NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
            [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
        }
    else {
        [challenge.sender cancelAuthenticationChallenge:challenge];
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    authenticated = YES;
    [connection cancel];
    [self.webView loadRequest:aRequest];
}

@end

  

  • 0x01: SSL 剥离攻击:网站并非全网 HTTPS,而只有需要进行明暗数据传输时才输入使用 HTTS 的漏洞。中间人攻击者在劫持了客户端与服务器的 HTTP 会话后,将 HTTP 页面所有的 https:// 超链接换成 http:// ,用户在点击相应的链接时,是使用 HTTP 协议来进行访问,这样,就算服务器对应的 URL 只支持 HTTPS 链接,但中间人一样可以和服务建立 HTTPS 链接之后,将数据使用 HTTP 协议转发给客户端,实现会话劫持。
    • 这种攻击手段更难以提防,因为它使用了 HTTP,不会让浏览器出现 HTTPS 证书不可信的警告,而且用户很少会起看浏览器上的 URL 是 https:// 还是 http:// 。特别是 App 的 webView中,一般把 URL 隐藏掉,用户无法直接查看 URL 出现异常。
    • 防范措施:

      1)这种攻击方法无法劫持 App 内的 HTTPS 连接会话,但在 webView 中打开网页需要注意,在非全网 HTTPS 的网站,建议对 WebView 中打开的 URL 做检查,检查应该使用 https:// 的 URL 是否被篡改为 http://。

      2)建议服务器在配置 HTTPS 服务时,也加上 "HTTP Strict Transport Security" 配置项。

 

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {

    NSURL* baseURL = [NSURL URLWithString:@"https://google.com"];
    if ([challenge.protectionSpace.host isEqualToString:baseURL.host]) {
        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        SecTrustResultType result;
        
        OSStatus status = SecTrustEvaluate(trust, &result);
        if ((status == errSecSuccess) &&
            ((result == kSecTrustResultProceed) ||
             (result == kSecTrustResultUnspecified))) {
                
                NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
                [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
            }
        else {
            // 3)验证失败,取消这次验证流程
            [challenge.sender cancelAuthenticationChallenge:challenge];
        }
    }
    else {
        [challenge.sender cancelAuthenticationChallenge:challenge];
    }
}

  

  • 0x02: 针对 SSL 算法进行攻击: 上述两种方式,技术含量较低,而且一般只影响 WebApp,很难攻击 Native App,所以高阶的 Hacker,会直接针对 SSL 算法相关漏洞进行攻击,期间会使用很多密码学相关手段。

      1)只支持尽量高版本的 TLS;

      2)禁止一些已爆出安全隐患的加密方法;

      3)使用 2048 位的数字证书;

  中间人攻击的模拟实验参考

 

     

二、正确的检验证书方法

  • 域名验证

    iOS 系统 API 是默认开启 validateDomainName 的,但注意 AFNetworking 在 2.5.2 以前存在漏洞,ValidatesDomainName 默认为 No,也就是只要是可信的 CA 机构签发,都校验通过。

  • 检验证书链 (讨论 AFNetworking 中 validatesCertificateChain 的问题)

    1) 在 AFNetworking V2.6.0 已经删除掉该属性;

    2) 是将 App 本地打包好的证书与服务器返回的证书进行数据的一一对比,只有打包到 App的证书中包含了服务器返回的证书链上的所有证书,校验才会通过。

      也就是说,开启了 validatesCertificateChain 后,访问 https://google.com,需要将 GeoTrust Global CA、Google Intenet Authority G2、google.com 的证书都倒入到 App 中才能验证通过。(不过这是完全没有必要的)

    

  • 打包证书校验

  用户设置系统信任证书,会作为锚点证书 (Anchor Certificate) 来验证其他证书,当返回的服务器证书是锚点证书或基于该证书签发的证书都会被信任。这就是基于信任链校验方式的最大弱点。我们不能完全相信系统的校验,因为系统的校验依赖的证书源可能被污染了。这就需要选取一个节点证书,打包到 App 中,作为 Anchor Certificate 来保证证书链的唯一性和可靠性。

SecTrustSetAnchorCertificates(SecTrustRef trust, CFArrayRef anchorCertificates)

  如果单纯调用了 SecTrustSetAnchorCertificates 方法后不调用 SecTrustSetAnchorCertificatesOnly 来验证证书,则只会相信 SectrustAnchorCertificates 传入的证书,而不会信任其他锚点证书。这意味着只相信传入的锚点证书,也就是只会验证通过由这些锚点证书签发的证书。这样就算被验证的证书是由系统其他信任的锚点证书签发,也无法验证通过。

  对于自建证书来说,选择哪一个节点都可以,而对于 CA 颁发的证书,则建议导入颁发该证书的 CA 机构证书或者更上一级的 CA 机构证书,甚至可以是根证书。原因是:

    1)叶子证书有限期较短

    2)越往证书链的末端,证书越有可能变动;

 

四、调试 SSL/TLS

  • SSL 相关的错误码在 <Security/SecureTransport.h> 中定义;
  • 这一阶段的不能使用 charles 来抓包分析了,因为 Charles作为 HTTP 代理工作的,它会抓取代理的网络,然后将报文组合成 HTTP/HTTPS 协议包,对于 HTTP 非常方便,但对于细节的缺失,没办法使用它来分析 SSL 相关的错误,需要使用 wireshark(介绍使用的文章)。
  • 有时候抓取的包只有 client hellod 和  serverhello。再没有发送证书的,也就是 SSL 和 TLS 的 session 重用。

 

 五、

posted on 2016-06-23 11:12  EileenLeung  阅读(418)  评论(0编辑  收藏  举报