react-native-ssl-public-key-pinning: [Bug][iOS] Not working with expo-dev-client in debug build
Hi, About 1-2 months ago, I had used this library to enforce SSL pinning in my company’s app on a PoC branch, which worked as expected.
And just today, I tried to install and apply the library again in a new branch, but now it does not block any request to pinned domain when using invalid keys.
Already run cd ios && pod install then expo run:ios
UPDATE (2024-01-24):
- Also opened an issue in TrustKit repo.
- Created a test repo in attempt to reproduce the issue, but still can’t: test-expo-ssl-pinning-1
- Tried with Android and it shows
Certificate pinning failure!error message as expected.
Configuration
(Testing invalid keys case)
{
"some-service.tech": {
"includeSubdomains": true,
"publicKeyHashes": [
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB="
]
}
}
Logs
(iOS to MacOS Console log)
=== TrustKit: Successfully initialized with configuration {
TSKPinnedDomains = {
"some-service.tech" = {
TSKDisableDefaultReportUri = 1;
TSKEnforcePinning = 1;
TSKIncludeSubdomains = 1;
TSKPublicKeyHashes = "{(\n {length = 32, bytes = 0x00000000 00000000 00000000 00000000 ... 00000000 00000000 },\n {length = 32, bytes = 0x04104104 10410410 41041041 04104104 ... 04104104 10410410 }\n)}";
kSKExcludeSubdomainFromParentPolicy = 0;
};
};
TSKSwizzleNetworkDelegates = 0;
}
Versions
- react-native-ssl-public-key-pinning: 1.1.3
- TrustKit: 3.0.3
- Axios: 0.25.0
- Expo: 49.0.13
- RN: 0.72.6
- CocoaPods: 1.14.3
- iOS: 16.2 (iPhone Simulator)
Thanks!
About this issue
- Original URL
- State: open
- Created 6 months ago
- Comments: 26 (9 by maintainers)
Commits related to this issue
- docs: add instructions to disable expo-dev-client network inspector to README.md Addresses #223 — committed to frw/react-native-ssl-public-key-pinning by frw 5 months ago
@oottoohh Yes I will try to fix this issue, though I will need to do a little bit of digging around to see how I can make it work nicely with expo-dev-client.
@cristian1206 In terms of security, I would highly recommend the OTA update option since you can sign the OTA bundle (CodePush, Expo Updates), ensuring that they are from a trusted source. If you’re updating your keys via an unpinned network request during startup, I believe you will be exposing a potentially security hole, since a bad actor would be able to perform a MitM attack and thus would be able to serve whatever keys they wish.
That’s great to hear that your setup works properly now!
Depending on TrustKit 2.0.1 shouldn’t be a problem, but I would advise you to update to the latest version by removing
pod 'TrustKit', '> 2.0.1'and then doingpod updatesince TrustKit is now at version 3.0.3 and there may have been bugfixes in between.Thanks! I’ve built the original app for iOS simulator using EAS, and when running the build on simulator, SSL pinning is enforced as designed. So this should work correctly on production.
Seems like it is caused by
expo-dev-client. I’m taking a look around theexpo-dev-clientcode and I’m noticing that Expo is swizzling the URLSessionConfiguration and intercepting network requests, which might be why the pinning configuration is getting ignored whenexpo-dev-clientis used.Let me see what options are available to hook into Expo’s
URLSessionso we can enable pinning even when usingexpo-dev-clientOtherwise, it seems like
expo-dev-clientonly intercepts network requests in development mode, so you should be fine if you’re building your app for production. Could you try building your app for production with the wrong keys and see if pinning is working fine?Notes
Might be related to: https://github.com/expo/expo/issues/24096
Will try to reproduce by adding
expo-updatesandexpo-dev-client@cristian1206 @frw Thanks! I’d try applying the pins at the first entrypoint of application and see if that works.
(I’m also suspecting some 3rd party SDKs that 'd get initialized in
AppDelegate.mmmight cause networking resources to be set up before pinning.)Hello @frw , thank you very much for your prompt response, what a shame I didn’t see the known issues section. In my case I am reviewing the issue of updating keys since I was trying to implement a request at the beginning that would bring me the new keys but with this issue that is presented in iOS I think it is going to be an inconvenience, I am going to review the updates via OTA Let’s see if I can find something on that side. Thank you very much again for your response.
@cristian1206
Thanks for the investigation into the issue. Indeed, iOS maintains a session cache, which re-uses connections if they’ve been made successfully before. This is detailed in the Known Issues section in the README: https://github.com/frw/react-native-ssl-public-key-pinning?tab=readme-ov-file#known-issues
The main workaround would be to ensure you initialize the pinning before any network requests are made.
@quaos are you still facing an issue with the pinning, taking this into consideration?
After performing several tests and researching various forums, I found the following:
When the request is made to any domain even without initializing trustkit, it seems that NSURLSession maintains its own TLS session cache. This means that if I initialize trustkit again, this configuration will not be taken and the new validation will not be done with my new keys.
The test done to determine this was:
Request without initializing trustkit.
Initialize trustkit.
Request to the same domain. In this case, truskit does not validate that connection again.
Note: I updated this post because by testing the instructions given by this blog https://developer.apple.com/library/archive/qa/qa1727/_index.html, I found that indeed when waiting for 10 minutes and performing a new request, validation was carried out again with the trustkiy pins