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

I've filed an issue as well: 22127901

Thank you.

Is there any indication of when this might be addressed?

Which issue specifically? There's a bunch of related issues covered by this thread, all of which have workarounds, although some are less satisfactory than others.

However, as far as future changes to the OS are concerned, that's not something I can speculate on; DTS Engineers aren't issued with a crystal ball, alas.

Share and Enjoy

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

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

Sorry, specifically I meant the top level issue of local requests being blocked by default w/ ATS. The common theme seems to be that yes, you can add a plist exception for it, but it would be cleaner to allow localhost by default and have the exception be to block it. I was just asking in case you'd be able to share any known changes coming in the next beta/release.

I meant the top level issue of local requests being blocked by default w/ ATS.

Hence my request for clarification. I'd argue that the top level issue here, the one raised by the hhtouch when they opened the thread, relates to accessing nearby networks not to accessing localhost.

Regardless, on the localhost front, it seems that bwalker filed a perfectly reasonable enhancement request for that (21519087) and there's a perfectly reasonable workaround (adding a ATS exception), so it's really just a question of waiting to see what iOS Engineering makes of the issue.

I was just asking in case you'd be able to share any known changes coming in the next beta/release.

You'll find that Apple folks really don't like discussing the future, even the relatively near future like the iOS 9 beta release cycle.

Share and Enjoy

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

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

Not working here anymore...was working last Thursday the 13th, stopped on Friday.


Anyone else notice that this doesn't work anymore...


  1. <key>NSAppTransportSecurity</key>
  2. <dict>
  3. <key>NSAllowsArbitraryLoads</key>
  4. <true/>
  5. </dict>

Not working here anymore […]

I retested this on iOS 9.0b5 and it’s working as expected. Specifically:

  1. I wrote a tiny test program that fetches

    https://stanford.edu
    .
  2. I ran it without a

    NSAppTransportSecurity
    dictionary; the load failed (there’s a transcript of the error at the end of this email).
  3. I ran it with the

    NSAppTransportSecurity
    dictionary shown in my Jul 15 post; it worked.

Share and Enjoy

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

let myEmail = "eskimo" + "1" + "@apple.com"
2015-08-18 08:29:26.310 QTestbed[7515:5780925] task start
2015-08-18 08:29:26.983 QTestbed[7515:5781012] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
2015-08-18 08:29:26.985 QTestbed[7515:5780925] task error NSURLErrorDomain / -1200

NSAllowsArbitraryLoads is not disabling the App Transport Security for the Watch, I'm using Watch OS 2 Beta 5, XCode 7 beta 6.

Any ideas if this is gonna work for the Watch at some point?

NSAllowsArbitraryLoads is not disabling the App Transport Security for the Watch …

I think you need to start a new thread for this new topic. It took me a while to find your post in this long and complex thread, even though I knew it was there.

Share and Enjoy

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

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

Thanks for your response.

This is the new thread I created.
https://forums.developer.apple.com/message/45902#45902

+1 for


Suggestion: Introduce a key NSAllowsArbitraryLoadsLocalNetworkOnly. When this key is set to true, it allows unencrypted http communication between devices on the same local network (IPv4 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 and IPv6 fd00::/8, and 127.0.0.1 for development purposes).

+1 for


Suggestion: Introduce a key NSAllowsArbitraryLoadsLocalNetworkOnly. When this key is set to true, it allows unencrypted http communication between devices on the same local network (IPv4 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 and IPv6 fd00::/8, and 127.0.0.1 for development purposes).

+1


Suggestion: Introduce a key NSAllowsArbitraryLoadsLocalNetworkOnly. When this key is set to true, it allows unencrypted http communication between devices on the same local network (IPv4 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 and IPv6 fd00::/8, and 127.0.0.1 for development purposes).


This is a HUGE issue for our company. We need to upload firmware on our devices through http requests over the local network, and requiring these devices to have https servers running is onerous (if not impossible). We would like to implement ATS on our apps for non-local traffic, but are unable to.

To update on this issue, Apple engineering closed my enhancement request as Behaves Correctly. After pressing them on the issue, (I'm not sure I'm allowed to publish bug report responses here in a public forum so I'll paraphrase) the response that they gave in support of denying localhost by default was an example of a linked advertising framework which secretly communicates with localhost and sends data to a remote server. If localhost is denied by default, then the developer can see this is happening.


Frankly, it seems overzealous; developers should already be running good firewall software which would alert them to the same thing. But it appears that ship has sailed and we're stuck with putting localhost exemptions in every project.


The OP's issue seems more pressing and the only workaround of "**** ATS from orbit" is not a workaround at all. Communicating with local devices, or testing apps on devices with local servers, is kind of fubar'd at the moment when IP addresses aren't accepted as valid exemptions.

One workaround is to edit the /etc/hosts file on your Mac and add a line like this at the end of the file (you need to do this as superuser/root):

127.0.0.1 apple.ninja


This makes "localhost" accessible via a fully qualified hostname (apple.ninja) and you can use the standard ATS feature to allow HTTP traffic to that "domain":


<key>NSAppTransportSecurity</key>
        <dict>
                <key>NSExceptionDomains</key>
                <dict>
                        <key>apple.ninja</key>
                        <dict>
                                <key>NSIncludesSubdomains</key>
                                <true/>
                                <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
                                <true/>
                        </dict>
                </dict>
        </dict>

While researching this as part of an official DTS incident I came across a reasonably nice workaround that I thought I’d share: namely, if the target device supports Bonjour you can add an ATS exception for “local” and everything within “local” will just work.

As part of its operation Bonjour service discovery requires that every device has a .local name. Specifically, when you resolve a service you get back:

  • the device’s .local name (A) — In NSNetService, this is the

    hostName
    property
  • the IP addresses associated with that name (B) — In NSNetService, this is the

    addresses
    property.
  • the port number on which to connect (C) — In NSNetService, this is the

    port
    property.

For example, if I browse for HTTP services on my local network:

$ dns-sd -B _http._tcp. local.
Browsing for _http._tcp..local.
DATE: ---Thu 15 Oct 2015---
11:01:51.968  ...STARTING...
Timestamp     A/R    Flags  if Domain   Service Type    Instance Name
11:01:51.969  Add        3   4 local.   _http._tcp.     Darth Inker
^C

I get back a list of services including

Darth Inker
. If I resolve that:
$ dns-sd -L "Darth Inker" _http._tcp. local.
Lookup Darth Inker._http._tcp..local.
DATE: ---Thu 15 Oct 2015---
11:02:42.973  ...STARTING...
11:02:43.289  Darth\032Inker._http._tcp.local. …at… darth-inker.local.:80 …
^C

I get the .local name (

darth-inker.local.
, point A) and the port number (80, point C). Finally, I can resolve the .local name into IPv4 and IPv6 addresses (point B).
$ dns-sd -q darth-inker.local. A
DATE: ---Thu 15 Oct 2015---
11:03:38.570  ...STARTING...
Timestamp     A/R Flags if Name                 Type  Class   Rdata
11:03:38.571  Add     2  4 darth-inker.local.   Addr   IN     192.168.1.40
^C
$ dns-sd -q darth-inker.local. AAAA
DATE: ---Thu 15 Oct 2015---
11:03:41.963  ...STARTING...
Timestamp     A/R Flags if Name                 Type  Class   Rdata
11:03:41.963  Add     2  4 darth-inker.local.   AAAA   IN     FE80:0000:00…
^C

The point here is that I don’t need to use these IP addresses in order to connect to the service. I can simply put the .local name into a URL and pass that URL to NSURL{Session,Connection}.

This is relevant for ATS because, if you always connect via the .local name, you can add an ATS exception for everything in the “local” domain (see below) and ATS will get out of the way.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>local</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
</dict>

Obviously this only works if the target device supports Bonjour but, hey, in my opinion, devices without Bonjour support are broken anyway (-;

Share and Enjoy

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

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

Another relatively simple workaround is xip.io, which may be more useful for many applications. A DNS call to (for example) 10.0.1.8.xip.io will resolve to 10.0.1.8, allowing use of the domain instead of the IP address for the NSExceptionDomains key.


By the way, NSAllowsArbitraryLoads did not work for me either. However, the xip.io workaround is sufficient for me (and superior to localhost).