App Transport Security (ATS) blocking https request to valid server, only in production build testflight

Hi,

We are developing react native app, and we are having issue with ATS policy in production build distributed to TestFlight internal testing, requests to https are being killed. The preview build ad-hoc distribution is working fine. (I am testing the app on physical device)

I will described what I've tried and supply you with logs from different tools.

  1. I tried to disable ATS - requests are working
  2. enable ATS (no change to default config) - requests are failing with following error
  Task <55618987-64A8-4C04-9B00-2EFF074D796C>.<1> finished with error [-1022] Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection., NSErrorFailingURLStringKey=<private>, NSErrorFailingURLKey=<private>, _NSURLErrorRelatedURLSessionTaskErrorKey=<private>, _NSURLErrorFailingURLSessionTaskErrorKey=<private>, NSUnderlyingError=0x30127bb10 {Error Domain=kCFErrorDomainCFNetwork Code=-1022}}
  1. I tried to check server if it had met ATS requirements and ran ats-diagnostic
./TLSTool s_client -connect api.rankacy.com:443
*  input stream did open
* output stream did open
* output stream has space
* protocol: TLS 1.2
* cipher: ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
* trust result: unspecified
* certificate info:
*   0 + ecPublicKey 256 ecdsa-with-SHA384 'api.rankacy.com'
*   1 + ecPublicKey 384 sha256-with-rsa-signature 'E6'
*   2 + rsaEncryption 4096 sha256-with-rsa-signature 'ISRG Root X1'
nscurl https://api.rankacy.com/ --verbose --ats-diagnostics
Starting ATS Diagnostics

Configuring ATS Info.plist keys and displaying the result of HTTPS loads to https://api.rankacy.com/.
A test will "PASS" if URLSession:task:didCompleteWithError: returns a nil error.
================================================================================

Default ATS Secure Connection
---
ATS Default Connection
ATS Dictionary:
{
}
Result : PASS
---

================================================================================

Allowing Arbitrary Loads

---
Allow All Loads
ATS Dictionary:
{
    NSAllowsArbitraryLoads = true;
}
Result : PASS
---

================================================================================

Configuring TLS exceptions for api.rankacy.com

---
TLSv1.3
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionMinimumTLSVersion = "TLSv1.3";
        };
    };
}
Result : PASS
---

---
TLSv1.2
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionMinimumTLSVersion = "TLSv1.2";
        };
    };
}
Result : PASS
---

---
TLSv1.1
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionMinimumTLSVersion = "TLSv1.1";
        };
    };
}
Result : PASS
---

---
TLSv1.0
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionMinimumTLSVersion = "TLSv1.0";
        };
    };
}
Result : PASS
---

================================================================================

Configuring PFS exceptions for api.rankacy.com

---
Disabling Perfect Forward Secrecy
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionRequiresForwardSecrecy = false;
        };
    };
}
Result : PASS
---

================================================================================

Configuring PFS exceptions and allowing insecure HTTP for api.rankacy.com

---
Disabling Perfect Forward Secrecy and Allowing Insecure HTTP
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionAllowsInsecureHTTPLoads = true;
            NSExceptionRequiresForwardSecrecy = false;
        };
    };
}
Result : PASS
---

================================================================================

Configuring TLS exceptions with PFS disabled for api.rankacy.com

---
TLSv1.3 with PFS disabled
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionMinimumTLSVersion = "TLSv1.3";
            NSExceptionRequiresForwardSecrecy = false;
        };
    };
}
Result : PASS
---

---
TLSv1.2 with PFS disabled
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionMinimumTLSVersion = "TLSv1.2";
            NSExceptionRequiresForwardSecrecy = false;
        };
    };
}
Result : PASS
---

---
TLSv1.1 with PFS disabled
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionMinimumTLSVersion = "TLSv1.1";
            NSExceptionRequiresForwardSecrecy = false;
        };
    };
}
Result : PASS
---

---
TLSv1.0 with PFS disabled
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionMinimumTLSVersion = "TLSv1.0";
            NSExceptionRequiresForwardSecrecy = false;
        };
    };
}
Result : PASS
---

================================================================================

Configuring TLS exceptions with PFS disabled and insecure HTTP allowed for api.rankacy.com

---
TLSv1.3 with PFS disabled and insecure HTTP allowed
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionAllowsInsecureHTTPLoads = true;
            NSExceptionMinimumTLSVersion = "TLSv1.3";
            NSExceptionRequiresForwardSecrecy = false;
        };
    };
}
Result : PASS
---

---
TLSv1.2 with PFS disabled and insecure HTTP allowed
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionAllowsInsecureHTTPLoads = true;
            NSExceptionMinimumTLSVersion = "TLSv1.2";
            NSExceptionRequiresForwardSecrecy = false;
        };
    };
}
Result : PASS
---

---
TLSv1.1 with PFS disabled and insecure HTTP allowed
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionAllowsInsecureHTTPLoads = true;
            NSExceptionMinimumTLSVersion = "TLSv1.1";
            NSExceptionRequiresForwardSecrecy = false;
        };
    };
}
Result : PASS
---

---
TLSv1.0 with PFS disabled and insecure HTTP allowed
ATS Dictionary:
{
    NSExceptionDomains =     {
        "api.rankacy.com" =         {
            NSExceptionAllowsInsecureHTTPLoads = true;
            NSExceptionMinimumTLSVersion = "TLSv1.0";
            NSExceptionRequiresForwardSecrecy = false;
        };
    };
}
Result : PASS
---

I am running out of ideas. Also it's hard to test because the preview ad-hoc build is working fine. So only after submitting the app to TestFlight I am having this issue

Looking for your response

Martin

Answered by Martin_S in 799719022

Hi,

So in the end I was able to figure it out, by using CFNetwork profile on my phone and gather the logs from production app https://developer.apple.com/bug-reporting/profiles-and-logs/?name=netw

Turned out that the request url was different from the one we set in env vars. Looks like a cache issue in 3rd party build service

Thank you for your previous responses

Martin

Are you using the Xcode organiser to submit your TestFlight build?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hi Eskimo,

We are using expo managed workflow so the builds are submitted to apple connect with eas services. I am not sure what do you mean by Are you using the Xcode organiser to submit your TestFlight build? The app is not crashing just requests are failing.

Looking for your response

Martin

Most iOS developers using the Xcode organiser to submit their builds to App Store Connect. See Distributing your app for beta testing and releases for a description of how that’s done.

This workflow allows you to export a build that matches the build that you submit to App Store Connect. You can use that to debug problems like this. The basic idea is:

  1. Export the build that’s having the problem.

  2. Unpack that archive.

  3. Look at the app’s Info.plist to see if it’s set up correctly.

You can also use this to distinguish between code-signing and build problems, as I describe in Isolating Code Signing Problems from Build Problems.

If you’re using third-party tools to build your app and those tools don’t involve the Xcode organiser then you can’t use my standard debugging techniques. And, sadly, that’s about as far as I can help you. I don’t maintain expertise in third-party tooling.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hi Eskimo,

I am sorry for late reply

As you mentioned I've exported the build and l've looked inside the Info.plist

So you can see the ATS is enabled, maybe the local network is the issue in production build?

Our BE service is compliant based on the first logs I gave you so it's quite confusing that default settings are not correct.

I've also tried the check/test tool in Xcode and it was fine, no issues found

Looking for your response

Martin

Accepted Answer

Hi,

So in the end I was able to figure it out, by using CFNetwork profile on my phone and gather the logs from production app https://developer.apple.com/bug-reporting/profiles-and-logs/?name=netw

Turned out that the request url was different from the one we set in env vars. Looks like a cache issue in 3rd party build service

Thank you for your previous responses

Martin

App Transport Security (ATS) blocking https request to valid server, only in production build testflight
 
 
Q