This article uses Swift and is accompanied by official documentation

Recently, I received A project (from company A). In addition, the school is busy with all kinds of things and it has been quite A long time since the last article. Because of the minor problems with this project, I wanted to write notes.

A, cause

Company A has an Intranet only document system. So far, it’s been purely Windows apps that use “URL Scheme” to drop data with the system, while I’m responsible for writing an IOS App that does the same thing. However, I was contracted, so I could not test the system under the internal network of Company A. After some discussion, they decided to make A test system on the Windows VIRTUAL machine, and I executed the system on the Mac, which means that I had the same internal network with the system.

2. Pre-test 🖥️

Assume that each Intranet IP address is as follows:

Mac: (A) 192.168.1.1

(B) Windows VM on Mac :192.168.1.2

(C) Real Iphone: 192.168.1.3

(D) website: https://192.168.1.2:8888/Domain

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

A preview D -> OK 👌, B preview D -> OK 👌

So let’s take a look at what I’m going to say about C preview D

Question 1 (UIWebView preview D) 🤔

  • The first attempt is to use WebView. Why do you choose WebView?

    This is because the owners don’t want to switch between two apps too much (they might jump two or three times in a process), and they don’t want users to be stuck in the system’s pages the next time they open Safari.

  • NSURLErrorDomain: – 1003?

    When I saw the ErrorDomain, I didn’t think much about it. I directly thought that it should be because MY DNS was not set properly, so I restarted the VIRTUAL machine and restarted the platform. ! @ #! $🙄 🙄

  • Safari enabled?

    I started using Safari all of a sudden because I didn’t want to keep rebuilding. I wanted to say it was the same.

    Press “Continue” to display the system page!

  • Evidence of distrust

    With this popup reminder, I realized that the crux of the problem was “credentials”, which was a new setting in IOS9: App Transport Security (ATS).

    ATS Reference website: https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.htm l#//apple_ref/doc/uid/TP40009251-SW33

    Basically, ATS is designed to make your App more secure by blocking two things: Http without Security and Https without trusting credentials, so you don’t inadvertently run into phishing sites and things like that.

Three, problem one solution 📖

  • Set up Info. Plist

    The first method is to simply turn off the ATS and add one of the following Key Value pairs to info.plist

    1.Allow Arbitary Loads (NSAllowArbitrayLoads)

    Is it used for? Its all attachment ATS, here refers to all the attachment including the URLRequest, URLConnection, URLSession UIWebView… And so on.

    But it is also stated in the official document that as long as the value of Allow Arbitary Loads is set to True, there is no way to pass the shelf review, so I do not use this method.


    2. The Exception Domain (NSExceptionDomains)

    Is it used for? Exclude a Domain from the ATS. Personally, I think this Key is a good one to use if you know you’re going to be under a certain Domain. I wonder if this Key will affect the shelves?

    Official documents: https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.htm l#//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

    Another approach is to implement the “Trust Customization for Specific APIs” in the official documentation, which is to customize the credence-checking for a requirement

    1.URLSession

    According to the official document, we need to practice urlSession (_ : task: didReceive: completionHandler:), if the certificate cannot verify, issued a Challenge for you to judge what you have to refuse the attachment or provide a proof to solve:

    • To observe the URLSessionDelegate

      let session = Foundation.URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
      Copy the code
    • Processing – “Challenge”

      challenge : URLAuthenticationChallenge

      The word Challenge is not unique to ios or CocoaFrameWork. Instead, it is the “challengeresponse authentication” issued by servers to users on the Internet. It is a protocol used to authenticate users or network providers. Will ask the user to return some information, account number, password, credentials… Etc., which ones will be described below.

      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)
      Copy the code

    { //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 - > contains the authentication request host, port... So that you can determine what **credential ** to deal with. 2.***authenticationMethod*** : This is the method I just mentioned that the server requires authentication, and this method determines what to do next, like: NSURLAuthenticationMethodHTTPBasic: asking users back account and password, and we have to deal with is NSURLAuthenticationMethodServerTrust, require users to back a certificate. 3.***URLCredential*** : This class has several very different Init() methods, mainly looking at the authenticationMethod to determine what you're sending back. ! [image.png](http://upload-images.jianshu.io/upload_images/3776017-a0fe3c2e078cbed5.png? ImageMogr2 /auto-orient/strip% 7cImageView2/2 /w/1240) We want to do the credentialprocessing this time, so we use the second construct. >https://developer.apple.com/reference/foundation/urlprotectionspace/nsurlprotectionspace_authentication_methods ***AuthChallengeDisposition** : Indicates behavior, including using credentials, canceling the request, executing default actions... Use. UseCredential. 5. Use completionHandle to tell the result :(using a credential, this credential)Copy the code

    2.UIWebView – Back to business we need to use UIWebView, but the official document states that we cannot customize Https server Trust, but we still need to use the above method.

    The tricky part is that UIWebView can only LoadingRequest and manage URLSession, so it has to take a detour.

  • The UIWebViewDelegate implementation remembers the failed Request and establishes a 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)! }} ' '* although that isURLSessionBut the two usages are actually the same, so we abide by themNSURLConnectionDelegateAnd at the end reLoadingAt a timeRequestThat's the same thingRequestIt will pass. ```swiftfunc 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!). } ` ` `Copy the code