(IOS)如何处理不受信任的http网路凭证 (WebView,下载档案)

本篇使用Swift 并附上官方文档

前阵子接了(公司A)一个专案,再加上要毕业了,学校各种忙碌,距离上一篇文章也有好大一段时间...,也是因为这个专案碰到了些小问题,才想来写写笔记。

一、起因

公司A有个只限内网用的公文系统(似乎是用java写的网页?),到目前为止都是单纯在Windows上的小程式利用『URL Scheme』跟这个系统互相丢接资料,我则是要负责写一个IOS App 跟此系统做一样的事。但我是承包的,无法在公司A的内网下测试,经过一番讨论,他们决定将系统做个测试用的灌在windows虚拟机上,我在Mac上执行就等于我跟这个系统相同内网。

二、前置测试 🖥️

假设各个内网ip如下:

(A)Mac:192.168.1.1

(B)Mac上的Windows虚拟机:192.168.1.2

(C)实机Iphone:192.168.1.3

(D)系统网址:https://192.168.1.2:8888/Domain

A ping B,C -> OK 👌、 B ping A,C -> OK 👌

A 预览 D -> OK 👌、 B 预览 D -> OK 👌

接下来让我们看看我要说的 C 预览 D 的状况

三、问题一 (UIWebView 预览 D) 🤔

  • 第一种尝试是利用WebView, 为什么首选它呢?

    因为业主不希望在两个App之间做过多的切换(一整个流程下来可能跳转两~三次),也不希望使用者在下次开启Safari时,还停留在系统的页面。

  • NSURLErrorDomain: -1003?

    WebView就在我LoadRequest时跳出这么一个错误,看到ErrorDomain时,我也没有多想,就直接认为应该是我DNS没设定好之类的问题,于是又重开了虚拟机,重启站台...!@#!$🙄🙄

  • Safari可开启?

    会突然使用Safari是因为我不想一直重新Build,内心想说结果一样,没想到,跳出来一个这样的提示:

    Safari开启系统

    按下"Continue"后,就显示出系统的页面了!

  • 不信任的的凭证

    有了这个弹窗的提醒,我才明白问题的症结点原来是“凭证”,原来是之前IOS9的新设定:App Transport Security (ATS)

    ATS参考网址:https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33

    基本上ATS就是为了要确保你的App更安全,会挡两样东西一个就是没有Security的Http一个是不信任凭证的Https,不会无意间跑到钓鱼网站之类的。

三、问题一解法📖

  • 设定Info.plist

    第一个方法最简单就是直接关掉ATS,直接在Info.plist增加以下其中一对Key Value Pair

    Info.plist
    1.Allow Arbitary Loads (NSAllowArbitrayLoads)
    用途是?解除所有连线的ATS限制,这里指的所有连线包括URLRequest,URLConnection,URLSession,UIWebView....等。

    但是官方文件里也很表明写了,只要Allow Arbitary Loads这个值被设为True,就没有办法通过上架审核,所以我不采用此方法。


    2.Exception Domain (NSExceptionDomains)

    用途是?排除某个Domain使其不受ATS的限制。
    个人认为这个Key比较适合拿来使用,如果你明确知道自己会在某个Domain之下的话。
    这个Key我不知道会不会影响上架?

    官方文档:https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35


  • HTTPS Server Trust Evaluation

    https://developer.apple.com/library/content/technotes/tn2232/_index.html#//apple_ref/doc/uid/DTS40012884-CH1-SECWEBVIEW

    另一种方法就是实作官方文档里的『Trust Customization for Specific APIs』,也就是自定义某个要求的凭证检查

    1.URLSession


    依照官方文档,我们需要实作 urlSession(_:task:didReceive:completionHandler:),如果凭证无法验证,会发出一个Challenge供你判断你要拒绝这个连线还是提供一个凭证来解决:

    • 遵守URLSessionDelegate

      let session = Foundation.URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
      
    • 处理 - 『Challenge』

      challenge : URLAuthenticationChallenge

      Challenge这个词并不是ios或CocoaFrameWork才有的,而是互联网中伺服器向使用者端发出的『Challenge–response authentication』,是一个用来验证用户或网络提供者的协议,会要求使用者回传一些资讯,帐号、密码、凭证...等,在下面会说说有哪些。

      https://developer.apple.com/reference/foundation/urlauthenticationchallenge

      https://zh.wikipedia.org/zh-cn/CHAP

      func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void)
      

    {
    //1
    let protectionspace = challenge.protectionSpace
    //2
    let authMethod = protectionspace.authenticationMethod
    if authMethod == NSURLAuthenticationMethodServerTrust
    {
    //3
    let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
    //4
    let input:URLSession.AuthChallengeDisposition = .useCredential
    //5
    completionHandler(input, credential)
    }
    }
    ```

     1.***Challenge.protectionSpace*** : URLProtectionSpace -> 包含了这个 authentication request的host,port...等,让你判断该用什么**credential(证书)**应付。
     
     2.***authenticationMethod*** : 这是我刚刚提到的,伺服器要求认证的方法,这个方法就会决定接下来要做的事,像是:NSURLAuthenticationMethodHTTPBasic:要求使用者回传帐号跟密码,而我们要处理的是NSURLAuthenticationMethodServerTrust,要求使用者回传一个凭证。
     
     3.***URLCredential*** : 这个类有几种差异满大的Init(),主要就是看authenticationMethod来决定你要回传的是什么。![image.png](http://upload-images.jianshu.io/upload_images/3776017-a0fe3c2e078cbed5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)我们这次要做的是凭证的处理,所以用第二个建构。
             
     >https://developer.apple.com/reference/foundation/urlprotectionspace/nsurlprotectionspace_authentication_methods
     
     4.URLSession.***AuthChallengeDisposition*** : 表示行为,包括要使用凭证、取消此次要求、执行预设动作...等列举,我们要用凭证所以用.useCredential。
     
     5.利用completionHandle告知结果:(使用凭证,这个凭证)
    

    2.UIWebView - 回归正题我们要用UIWebView,但官方文档即提到无法自定义Https server trust,但我们还是要用上面的方法解决。

    棘手的地方是UIWebView只能单纯LoadingRequest跟管理URLSession,必须绕道而行。

  • 实作UIWebViewDelegate记住失败的Request,并且建立一个URLConnection。

       func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool
  {
          LastRequest = request
          return true
  }
      
       func webView(_ webView: UIWebView, didFailLoadWithError error: Error)
  {
          FailRequest = LastRequest
          if(FailRequest != nil)
          {
              let _:NSURLConnection = NSURLConnection(request: FailRequest! , delegate: self)!
          }
  }
      ```
      
*   虽然刚刚讲的是URLSession,但两个用法其实是相同的,所以我们遵守NSURLConnectionDelegate,并在最后重新Loading一次Request,这样同个Request就可以通了。
      
  ```swift
      func connection(_ connection: NSURLConnection, willSendRequestFor challenge: URLAuthenticationChallenge)
      {
          if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust  {
          print("send credential Server Trust")
          let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
          challenge.sender!.use(credential, for: challenge)
      }
      else{
          challenge.sender!.performDefaultHandling!(for: challenge)
      }
          connection.cancel()
          SystemWebView.loadRequest(FailRequest!)
  }
  ```
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容