详解IOS如何防止抓包

编辑: admin 分类: ios开发 发布时间: 2021-12-12 来源:互联网
目录
  • 抓包原理
  • 防止抓包
    • 一、发起请求之前判断是否存在代理,存在代理就直接返回,请求失败。
    • 二、我们可以在请求配置中清空代理,让请求不走代理
  • SSL Pinning(AFN+SSL Pinning)推荐
    • 扩展

      抓包原理

      其实原理很是简单:一般抓包都是通过代理服务来冒充你的服务器,客户端真正交互的是这个假冒的代理服务,这个假冒的服务再和我们真正的服务交互,这个代理就是一个中间者 ,我们所有的数据都会通过这个中间者,所以我们的数据就会被抓取。HTTPS 也同样会被这个中间者伪造的证书来获取我们加密的数据。

      防止抓包

      为了数据的更安全,那么我们如何来防止被抓包。

      第一种思路是:如果我们能判断是否有代理,有代理那么就存在风险。

      第二种思路:针对HTTPS 请求。我们判断证书的合法性。

      第一种方式的实现:

      一、发起请求之前判断是否存在代理,存在代理就直接返回,请求失败。

      CFDictionaryRef dicRef = CFNetworkCopySystemProxySettings();
      CFStringRef proxyStr = CFDictionaryGetValue(dicRef, kCFNetworkProxiesHTTPProxy);
      NSString *proxy = (__bridge NSString *)(proxyStr);
      + (BOOL)getProxyStatus {
          NSDictionary *proxySettings = NSMakeCollectable([(NSDictionary *)CFNetworkCopySystemProxySettings() autorelease]);
          NSArray *proxies = NSMakeCollectable([(NSArray *)CFNetworkCopyProxiesForURL((CFURLRef)[NSURL URLWithString:@"http://www.baidu.com"], (CFDictionaryRef)proxySettings) autorelease]);
          NSDictionary *settings = [proxies objectAtIndex:0];
          
          NSLog(@"host=%@", [settings objectForKey:(NSString *)kCFProxyHostNameKey]);
          NSLog(@"port=%@", [settings objectForKey:(NSString *)kCFProxyPortNumberKey]);
          NSLog(@"type=%@", [settings objectForKey:(NSString *)kCFProxyTypeKey]);
          
          if ([[settings objectForKey:(NSString *)kCFProxyTypeKey] isEqualToString:@"kCFProxyTypeNone"])
          {
              //没有设置代理
              return NO;
          }
          else
          {
              //设置代理了
              return YES;
          }
      }

      二、我们可以在请求配置中清空代理,让请求不走代理

      我们通过hook到sessionWithConfiguration: 方法。然后清空代理

      + (void)load{
        Method method1 = class_getClassMethod([NSURLSession class],@selector(sessionWithConfiguration:));
        Method method2 = class_getClassMethod([NSURLSession class],@selector(px_sessionWithConfiguration:));
        method_exchangeImplementations(method1, method2);
      
        Method method3 = class_getClassMethod([NSURLSession class],@selector(sessionWithConfiguration:delegate:delegateQueue:));
        Method method4 = class_getClassMethod([NSURLSession class],@selector(px_sessionWithConfiguration:delegate:delegateQueue:));
        method_exchangeImplementations(method3, method4);
      }
      
      + (NSURLSession*)px_sessionWithConfiguration:(NSURLSessionConfiguration*)configuration delegate:(nullable id)delegate delegateQueue:(nullable NSOperationQueue*)queue
      {
            if(configuration) configuration.connectionProxyDictionary = @{};
      
        return [self px_sessionWithConfiguration:configuration delegate:delegate delegateQueue:queue];
      }
      
      + (NSURLSession*)px_sessionWithConfiguration:(NSURLSessionConfiguration*)configuration
      {
      
            if(configuration) configuration.connectionProxyDictionary = @{};
      
        return [self px_sessionWithConfiguration:configuration];
      }

      ​ 第二种思路的实现:

      主要是针对HTTPS 请求,对证书的一个验证。

      通过 SecTrustRef 获取服务端证书的内容

      static NSArray * AFCertificateTrustChainForServerTrust(SecTrustRef serverTrust) {
         CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
         NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];
      
         for (CFIndex i = 0; i < certificateCount; i++) {
             SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
             [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];
         }
      
         return [NSArray arrayWithArray:trustChain];
      }

      然后读取本地证书的内容进行对比

      NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"cer"];//证书的路径
      NSData *certData = [NSData dataWithContentsOfFile:cerPath];
      SSet<NSData*> * set = [[NSSet alloc]initWithObjects:certData  , nil];  // 本地证书内容
      // 服务端证书内容
      NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
      for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
          if ([set containsObject:trustChainCertificate]) {
              // 证书验证通过
          }
      }

      SSL Pinning(AFN+SSL Pinning)推荐

      SSL Pinning,即SSL证书绑定。通过SSL证书绑定来验证服务器身份,防止应用被抓包。

      1、取到证书

      客户端需要证书(Certification file), .cer格式的文件。可以跟服务器端索取。

      如果他们给个.pem文件,要使用命令行转换:

      openssl x509 -inform PEM -in name.pem -outform DER -out name.cer

      如果给了个.crt文件,请这样转换:

      openssl x509 -in name.crt -out name.cer -outform der

      如果啥都不给你,你只能自己动手了:

      openssl s_client -connect www.website.com:443 </dev/null 2>/dev/null | openssl x509 -outform DER > myWebsite.cer**

      2、把证书加进项目中

      把生成的.cer证书文件直接拖到你项目的相关文件夹中,记得勾选Copy items if neede和Add to targets。

      3、参数名意思

      AFSecurityPolicy

      SSLPinningMode

      AFSecurityPolicy是AFNetworking中网络通信安全策略模块。它提供三种SSL Pinning Mode

      /**

       ## SSL Pinning Modes

       The following constants are provided by `AFSSLPinningMode` as possible SSL pinning modes.

       enum {

       AFSSLPinningModeNone,

       AFSSLPinningModePublicKey,

       AFSSLPinningModeCertificate,

       }

       `AFSSLPinningModeNone`

       Do not used pinned certificates to validate servers.

       `AFSSLPinningModePublicKey`

       Validate host certificates against public keys of pinned certificates.

       `AFSSLPinningModeCertificate`

       Validate host certificates against pinned certificates.

      */

      AFSSLPinningModeNone:完全信任服务器证书;

      AFSSLPinningModePublicKey:只比对服务器证书和本地证书的Public Key是否一致,如果一致则信任服务器证书;

      AFSSLPinningModeCertificate:比对服务器证书和本地证书的所有内容,完全一致则信任服务器证书;

      选择那种模式呢?

      AFSSLPinningModeCertificate:最安全的比对模式。但是也比较麻烦,因为证书是打包在APP中,如果服务器证书改变或者到期,旧版本无法使用了,我们就需要用户更新APP来使用最新的证书。

      AFSSLPinningModePublicKey:只比对证书的Public Key,只要Public Key没有改变,证书的其他变动都不会影响使用。
      如果你不能保证你的用户总是使用你的APP的最新版本,所以我们使用AFSSLPinningModePublicKey。

      allowInvalidCertificates

      /**
       Whether or not to trust servers with an invalid or expired SSL certificates. Defaults to `NO`.
       */
      @property (nonatomic, assign) BOOL allowInvalidCertificates;

      是否信任非法证书,默认是NO。

      validatesDomainName

      /**
       Whether or not to validate the domain name in the certificate's CN field. Defaults to `YES`.
       */
      @property (nonatomic, assign) BOOL validatesDomainName;

      是否校验证书中DomainName字段,它可能是IP,域名如*.google.com,默认为YES,严格保证安全性。

      4、使用AFSecurityPolicy设置SLL Pinning

      + (AFHTTPSessionManager *)manager
      {
          static AFHTTPSessionManager *manager = nil;
          static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
          
              NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
              manager =  [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config];
      
              AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey withPinnedCertificates:[AFSecurityPolicy certificatesInBundle:[NSBundle mainBundle]]];
              manager.securityPolicy = securityPolicy;
          });
          return manager;
      }

      扩展

      Android 防止抓包

      1、单个接口访问不带代理的

      URL url = new URL(urlStr);  
      urlConnection = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); 

      2、OkHttp框架

      OkHttpClient client = new OkHttpClient().newBuilder().proxy(Proxy.NO_PROXY).build(); 

      以上就是详解IOS如何防止抓包的详细内容,更多关于IOS如何防止抓包的资料请关注海外IDC网其它相关文章!

      【文章出处:防ddos攻击