3

How can I disable App Transport Security only when I run my app on the simulator (while still keeping it enabled when I run my app on my device, even in Debug mode)? Is there a way to disable it with Swift code instead of by modifying the Info.plist file?

I'm asking because I've configured things (via the code snippet below) so that the simulator connects (over HTTP) to a development server running on localhost and the device connects (over HTTPS) to the production server running in the cloud.

#if arch(x86_64) || arch(i386) // simulator
let apiBaseURLString = "http://localhost:3000"
#else                          // device
let apiBaseURLString = "https://api.example.com"
#endif

Ideally, I'd like keep App Transport Security enabled on the simulator and have the simulator connect over HTTPS to the development server running on localhost. I had that working, but I just updated Xcode, and it broke.

ma11hew28
  • 121,420
  • 116
  • 450
  • 651
  • 2
    What is your rationale for doing this? Do you access different URLs when running in the Simulator vs. the device. Otherwise, you may as well add any appropriate ATS exceptions now so that you aren't pushing problems off to when you get to device testing. I do not believe there is a way to change the Info.plist at runtime, since it is part of the bundle, and the bundle should not be able to be changed. I would think the easier solution would be to create a new simulator specific build config with it's own Info.plist. – wottle Apr 06 '17 at 14:13
  • I think you should look into option 2 in my answer, specifically 'NSAllowsLocalNetworking'. – wottle Apr 08 '17 at 01:58
  • OK. I will. Thank you. Also, I just added the ideal solution to my question. – ma11hew28 Apr 08 '17 at 02:02
  • I'm assuming your development server ssl connection is using a self signed certificate? Those can be tricky. I think your best bet is to add the local networking exception to your info.plist. Or figure out a way to restore a valid ssl connection to your dev server. – wottle Apr 08 '17 at 02:12
  • Yes, it's using a self-signed certificate. I think I followed this: https://github.com/seviu/iOS-SSL-localhost. OK. Thank you. :-) – ma11hew28 Apr 08 '17 at 02:28

2 Answers2

2

App Transport Security is configured at compile time by reading in the Info.plist. Changing it at runtime would actually have no effect on ATS enforcement, even if you could change the Info.plist at runtime (which you can't).

I can only think of two solutions:

  1. Simulator build config -You could create two versions of the Info.plist, one of which disables ATS altogether, the other is used for running on devices. You can then create a specific build config for running on the simulator. In your Build settings, choose the new Info-Simulator.plist which disables ATS. The downside of this is that you would need to change your build config before running on the simulator - it would not automatically use the correct build config for simulator vs. devices.

  2. Don't have different ATS settings for the simulator. Configure ATS to handle both the Simulator and physical devices. There are many options for ATS exceptions that should work for most scenarios. Need exceptions for local network connections? Look into NSAllowsLocalNetworking. Need more flexibility in a webview? Try NSAllowsArbitraryLoadsInWebContent.

Unfortunately, you can detect the simulator at runtime, but you can't change ATS behavior at runtime. You'll need to find another way, or re-evaluate if you really need a different config on simulators vs. devices.

Community
  • 1
  • 1
wottle
  • 13,095
  • 4
  • 27
  • 68
  • Thank you. Great ideas! I have two concerns with solution 2: 1) Will I be able to use the simulator to test my app on iOS 9.0? 2) What are the consequences of enabling `NSAllowsLocalNetworking` on the release build (that gets installed on end users' devices)? – ma11hew28 Apr 08 '17 at 02:06
  • 1 Probably not. The local networking exception was added in iOS 10. 2. The impact would be if your app did try to connect to a resource on the local network it would not enforce ATS requirements. Since your production app wouldn't do that, it would have no impact. – wottle Apr 08 '17 at 02:15
  • Honestly, you're putting a lot of work and complexity into wanting to sometimes test against the local host. If it were me, I would go with option 1 and simply have one Info.plist that disables all ATS when I'm running against localhost. And another that leaves ATS on (no exceptions) when testing against the prod server. – wottle Apr 08 '17 at 02:17
  • OK. Thank you. According to [Apple: Developer: Guides and Sample Code: Information Property List Key Reference: Cocoa Keys: NSAppTransportSecurity: Availability of ATS for Remote and Local Connections](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW54): "Although ATS is unenforced for connection to local hosts, Apple strongly recommends using Transport Layer Security (TLS) for any local connection, along with the use of a self-signed certificate to validate the local IP address." – ma11hew28 Apr 08 '17 at 13:17
  • I'm going to figure out (again) how to get the simulator to connect over HTTPS to the development server running on localhost. – ma11hew28 Apr 08 '17 at 13:19
  • I would agree avoiding the exception, if you were shipping an app that would be connecting to a local network resource. You said you were just doing this for development. If so, use the exception during testing with your dev server, but take the exception out and test against the prod server before you submit to the store. – wottle Apr 09 '17 at 01:18
  • I figured out how to get the [iPhone simulator (running iOS 10.3) to connect over HTTPS to my development server running on localhost](http://stackoverflow.com/questions/43303168/ios-10-3-simulator-https-localhost-ssl-error). – ma11hew28 Apr 09 '17 at 04:54
-1

I think this Code should work to access the .plist file, upon this code you can make changes what you need and put condition for that.

Bundle.main.object(forInfoDictionaryKey: key_name)

UPDATE

Here I'm Posting an Image please folow it:

enter image description here

Here you can get the value for:

NSAllowsArbitraryLoads = 1;

And through this you can put a condition according to your requirement.

Thanks

Abhishek Mitra
  • 3,335
  • 4
  • 25
  • 46
  • 3
    The OP is asking to make changes to the values at runtime, not read the values at runtime. They want to disable ATS if being run within a simulator. – wottle Apr 06 '17 at 14:14
  • @wottle Yes you are right, I posted this for to bypass the situation, what he wanted, he can achieve through by putting the condition, I think here i did some immature thing :P Anyway, your explanation is great, thanks by the way. – Abhishek Mitra Apr 06 '17 at 14:18
  • Yes, unfortunately, The ATS enforcement cannot be modified at runtime, so even if they could read the Info.plist, they couldn't modify the behavior as is needed. – wottle Apr 06 '17 at 14:27
  • @wottle I think it can be possible, you can change the .plist data, not sure about run time, but it is possible to change then what's wrong with ATS ? it should be changed. – Abhishek Mitra Apr 06 '17 at 14:47
  • Because the Info.plist is read at compile time, changing it at run-time would have no effect on ATS behavior. Also, the Info.plist is copied into the bundle, which is signed and therefore cannot be changed at run time. – wottle Apr 06 '17 at 14:48