App Transport Security and local networking

Hi,


it seems that "App Transport Security" is also enabled by default for communication on the local network (http transfers between devices on the same wifi network).

In many cases such wifi devices (e.g. wifi based sd cards, mobile wifi harddisks) do not support https; so http needs to be used.

What is the recommended way to handle these cases as the domain based exception cant be applied here?
Is there any way to disable App Transport Security for private networks?


Cheers,


Hendrik

Replies

Very goood news. I tried iOS 10 beta both on the simulator and on an iPad and observed the same behavior with ".local." host names.


It seems that if you actually only use IP addresses, no exception is needed any more. My app was able to perform clear HTTP requests to 127.0.0.1 or 192.168.100.2 (a local network wifi address) without any ATS section in the app .plist file. So it seems that I could simply remove any ATS exception from the app and submit it as is in 2017.


This raised a question though: If I submit my app without ATS exception, which should work on an iOS 10 device, how will it behave if the app is installed on iOS 9?

If I submit my app without ATS exception, which should work on an iOS 10 device, how will it behave if the app is installed on iOS 9?

Clearly iOS 9 does not support

NSAllowsLocalNetworking
. If you want to support iOS 9 and 10, you’ll need to also set
NSAllowsArbitraryLoads
. Make sure you explain this to App Review as part of your “reasonable justification”.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Doesn't this defeat the purpose of the new iOS 10 exceptions: In order to maintain iOS 9 compatibility (A likely scenario for most apps submitted next year) the developer will have to request a broader exception even if not needed. If granted it effectively allows an app to use clear http anywhere.

Doesn't this defeat the purpose of the new iOS 10 exceptions …

What alternative do you propose?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

The new exception being tied to iOS 10 only I don't see any solution on the developer side. Would it be theorically possible for an app built with Xcode 8 compatible with iOS 10 and 9 to be processed by Apple before distribution so that the new exceptions (LocalNetworking) translate into the broader NSAllowsArbitraryLoads when installed on iOS 9? This way, at least the app developer does not have to request NSAllowsArbitraryLoads and justify it.

Once again, highly hypothetical.

Would it be theorically possible for an app built with Xcode 8 compatible with iOS 10 and 9 to be processed by Apple before distribution so that the new exceptions (LocalNetworking) translate into the broader

NSAllowsArbitraryLoads
when installed on iOS 9?

That’s an interesting idea. Feel free to write up an enhancement request along those lines.

JSYK, the latest ATS docs (the NSAppTransportSecurity section of Information Property List Key Reference in the pre-release reference library) specifically addresses the backwards compatibility issue.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Can you please elaborate on the comment re absolute domain name for local tld? If we refer to a domain

http://guy-smiley.local
will the phone perform a DNS lookup across the network to the DNS server?


I'd like to be able to use our DNS to respond to .local names (with an RFC1918 address - only accessible within our network), however normally an unqualified name would be turned into an FQDN (with a trailing dot) before the request is sent across the network to the DNS server, so how does it work with unqualified name on iOS?

… however normally an unqualified name would be turned into an FQDN (with a trailing dot) before the request is sent across the network to the DNS server …

Right, but ATS is not involved at the DNS level. ATS looks at the DNS name from the URL you pass to the request (NSURLRequest) that you start.

ps I hope you’re not using

local.
for site allocated DNS names. That domain is reserved for mDNS per RFC 6762.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hello

There is still no clear indication on how to handle both iOS 9 and 10 for a local network

For iOS 10, it's easy, we just need to use flag NsAllowsLocalNetworking.

OK, but this Flag is ignored on iOS 9. And our app need to be compatible with both iOS 9 and 10 after 1st january 2017.

Then on iOS 9 we have 3 solutions:

1. Set Flag NSAllowsArbitraryLoads. It purely disables ATS but this require App Store justification

2. For a specified domain, use flag NSExceptionAllowsInsecureHTTPLoads. But this requires App Store justification

3. For a specified domain, use flag NSThirdPartyExceptionAllowsInsecureHTTPLoads. From what i've read "unofficially" this would not require App Store justification. But this flag has been removed from official Apple documentation, then I guess we are no more allowed to use it.


It's urgent developers get from Apple a clear statement on how ATS must be configured for local network for both iOS 9 and 10 in order to pass App Store review.


Thanks

I don’t work for App Review and can’t make “a clear statement” on their behalf but the advice in the ATS docs seems pretty clear to me. Specifically, Table 2 says:

NSAllowsLocalNetworking
If you set this key’s value to
YES
, then App Transport Security ignores the value of the
NSAllowsArbitraryLoads
key in iOS 10 and later … This behavior supports adoption of App Transport Security protections while allowing embedded browsers to continue working in iOS 9 and earlier … (To obtain this behavior, set the value of this key to YES and set the value of the
NSAllowsArbitraryLoads
key to YES as well.)

As always, if you find the docs unclear, please file a bug against them.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I have the same requirements.

My application need to connect to local devices using IP: they support https but not latest protocol (the device is limited to TLS v1.1)

I have added NSAllowsLocalNetworking but it still fails in SSL verification.


How to solve this issue ?

NSAllowsLocalNetworking
only affects ATS; NSURLSession still does RFC 2818-style HTTPS server trust evaluation, and you’ll need to deal with that as well. Technote 2232 HTTPS Server Trust Evaluation describes how.

ps You might want to have a read of my TLS for App Developers post.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

This is not working for a local address that uses https `https://192.168.0.1`. In that case I still have to set `NSAllowsArbitraryLoads` to `YES`.

I'm crippled by this issue too and just read about NSAllowsLocalNetworking. So I added the following keys to my Apple Watch Extension's Info.plist, but it still fails:


  <key>NSAppTransportSecurity</key>
  <dict>
      <key>NSAllowsLocalNetworking</key>
      <true/>
  </dict>


All I'm trying to do is play a test video from my NAS (on my local network), but the following line of code shows "unable to read data" in the debugger while it merely tries to create a URL:


  let url = URL(string: "http://scenario-imac.local/~MyUserName/Volumes/iTunes/iTunes%20Media/TV%20Shows/Star%20Trek/Season%201/18%20Arena.m4v")!


If I po it, the url looks good. But then setting WKInterfaceMovie' url and pressing play fails to produce either video or an error.

URLs of that form work fine from my iOS and tvOS apps, but not from watchOS. Shouldn't watchOS 3.1 be respecting this key?

Hi

I have an iOS 10 (only) app. The app needs to be able to support the use of self-signed certifcates for IP addresses i.e https://192.168.2.1 in a "test" mode. The IP addresses and certifcates are spawned virtual servers and they don't have access to a DNS or a certificate authority, importantly they are for testing only.


In the app info.plist I have the following entry:

<key>NSAppTransportSecurity</key>
  <dict>
        <key>NSAllowsArbitraryLoads</key>
  <true/>
  </dict>


If the app is in "test" mode, this is the code that gets executed:

class AllowSelfSignedCertificate: NSObject, URLSessionDelegate
{
  private func urlSession(session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: (NSURLSession.AuthChallengeDisposition, URLCredential?) -> Void)
  {
    completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
  }
}

if mode == OperationMode.test
{
  let session = URLSession(configuration: URLSessionConfiguration.ephemeral, delegate: AllowSelfSignedCertificate(), delegateQueue: nil)
}


When I run the app in "test" mode I get the following error:
The certificate for this server is invalid. You might be connecting to a server that is pretending to be "192.168.2.1" which could put your confidential information
at risk


When I connect the app to the same network as the test server and include NSAllowsLocalNetworking, I get the same error. Following is the output of nsurl:

nscurl --ats-diagnostics https:/
Starting ATS Diagnostics
Configuring ATS Info.plist keys and displaying the result of HTTPS loads to https:/
A test will "PASS" if URLSession:task:didCompleteWithError: returns a nil error.
Use '--verbose' to view the ATS dictionaries used and to display the error received in URLSession:task:didCompleteWithError:.
================================================================================
Default ATS Secure Connection
---
ATS Default Connection
2016-12-28 14:52:50.763 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824)
Result : FAIL
---
================================================================================
Allowing Arbitrary Loads
---
Allow All Loads
2016-12-28 14:52:50.794 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Result : FAIL
---
================================================================================
Configuring TLS exceptions for 192.168.2.1
---
TLSv1.2
2016-12-28 14:52:50.830 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824)
Result : FAIL
---
---
TLSv1.1
2016-12-28 14:52:50.868 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824)
Result : FAIL
---
---
TLSv1.0
2016-12-28 14:52:50.934 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824)
Result : FAIL
---
================================================================================
Configuring PFS exceptions for 192.168.2.1
---
Disabling Perfect Forward Secrecy
2016-12-28 14:52:50.948 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Result : FAIL
---
================================================================================
Configuring PFS exceptions and allowing insecure HTTP for 192.168.2.1
---
Disabling Perfect Forward Secrecy and Allowing Insecure HTTP
2016-12-28 14:52:50.959 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Result : FAIL
---
================================================================================
Configuring TLS exceptions with PFS disabled for 192.168.2.1
---
TLSv1.2 with PFS disabled
2016-12-28 14:52:50.971 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Result : FAIL
---
---
TLSv1.1 with PFS disabled
2016-12-28 14:52:50.980 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Result : FAIL
---
---
TLSv1.0 with PFS disabled
2016-12-28 14:52:50.990 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Result : FAIL
---
================================================================================
Configuring TLS exceptions with PFS disabled and insecure HTTP allowed for 192.168.2.1
---
TLSv1.2 with PFS disabled and insecure HTTP allowed
2016-12-28 14:52:51.022 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Result : FAIL
---
---
TLSv1.1 with PFS disabled and insecure HTTP allowed
2016-12-28 14:52:51.041 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Result : FAIL
---
---
TLSv1.0 with PFS disabled and insecure HTTP allowed
2016-12-28 14:52:51.052 nscurl[36062:6500411] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Result : FAIL
---


When I run openssl -s_client, this is the output (certificate information omitted)

openssl s_client -connect 192.168.2.1:443
CONNECTED(00000003)
verify error:num=18:self signed certificate
verify return:1
---
No client certificate CA names sent
---
SSL handshake has read 979 bytes and written 456 bytes
---
New, TLSv1/SSLv3, Cipher is AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : AES128-SHA
    Session-ID: BC8C61C53D3BBBC9CEAEA468BCC54FA4C494C43192274A48E4195A80FDB36EDC
    Session-ID-ctx:
    Master-Key: 511F32CC76D8D7C457003B1042D9E678E159DC653D1F8AE844E6EA9A280727D0BA41E6329FFECFE628C1B8CC41EF71A0
    Key-Arg   : None
    Start Time: 1482901084
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)
---
read:errno=0


What ATS configuration should I adopt in the app to enable http://<ip_address> in a test operation mode?


Thanks for your help