Open endervad opened 3 years ago
I can't find anything from Google saying that ignoring certificate errors isn't allowed. Browsers let you do it, after all
I can't recall where I saw it (from Google) but it stated that apps that attempt to modify (specifically to reduce) security by providing a work-around like this would be violating the Play Store's policy because it puts the end user "at risk." It has to do with the API used to verifying certificates, that's what they check (edit: as I was informed at the time I ran into this issue a long while back with other apks, unrelated to signing). If it uses a custom function to bypass validation (what this does) then it's not allowed. badCertificateCallback
if I recall (edit: for this situation, I mean, that's the API used for Dart and such).
This wasn't where I saw the issue at all, it was from Google's own development docs. I can't find that info from memory, I do little Android development. A quick search popped that up demonstrating.
Relevant Snippet:
...application has an unsafe implementation of the WebViewClient.onReceivedSslError handler. Specifically, the implementation ignores all SSL certificate validation errors, making your app vulnerable to man-in-the-middle attacks. An attacker could change the affected WebView's content, read transmitted data (such as login credentials), and execute code inside the app using JavaScript. ... Apps with vulnerabilities that expose users to risk of compromise may be considered in violation of our Malicious Behavior policy and section 4.4 of the Developer Distribution Agreement. Please ensure all apps published are compliant with the Developer Distribution Agreement and Developer Program Policies. If you have questions or concerns, please contact our support team through the Google Play Developer Help Center.
You must present the error every time, though. If you want to get around that you need to add the CA as a cert (store it, append it, give the user a way to manage that, required) and load it on startup every time, or wait until the backend trusts the system store instead of loading its own certs or whatever screwy thing they're doing.
I'd argue a checkbox that's not checked by default and maybe hidden in an "advanced settings" menu is not a "vulnerability that exposes users to risk", it's a compatibility option.
In any case, if it's not too much work to implement that handler, we should just try and see what Google says...
I'd argue a checkbox that's not checked by default and maybe hidden in an "advanced settings" menu is not a "vulnerability that exposes users to risk", it's a compatibility option. In any case, if it's not too much work to implement that handler, we should just try and see what Google says...
That's literally all you have to do, make it a non-default option. Just overriding to accept all without informing the user and allowing them to reject/prevent is what Google won't allow. Having it as an option that is off by default is what they want. I felt the easiest way to implement the fix regardless of the backend's support was to quite literally attempt connection and if ERR present the cert chain[0] (will be root of cert-chain if using custom CA or will be self-signed, etc) info to allow user to connect or to connect and add the thumbprint to an allowlist (to allow 'do not show again for this server' functionality, can compare the thumbprint and allow). Allow managing that list, rather simple. I'd write the code myself if Android Studio didn't suck so much as an IDE. Better would be to store the cert itself and add as trusted CA. For cert chains, present each cert.
@OdinVex feel free to write the code, no need to use Android Studio. VS Code is all you need. But I don't think the allowlist and thumbprint detection is as easy as it seems. This is a cross-platform framework, almost nothing is consistent or easy to access when it comes to low-level functionality...
@OdinVex feel free to write the code, no need to use Android Studio. VS Code is all you need. But I don't think the allowlist and thumbprint detection is as easy as it seems. This is a cross-platform framework, almost nothing is consistent or easy to access when it comes to low-level functionality...
The code took 15 minutes to write. It's the \<screaming rampage> UI \<new curse words> stuff that's in my way. I've already implemented it in Finamp's Settings, the callback to detect if it's been approved before,, etc. Presents simple dialogs to confirm connection, warn if the cert changed, stores per host and per port and per cert thumbprint. Edit: As for VS Code, I don't touch MicroJunk's stuff.
@OdinVex if you already have mostly working code, why not open a draft PR so we can take a look and get it ready to merge? :)
@OdinVex if you already have mostly working code, why not open a draft PR so we can take a look and get it ready to merge? :)
The UI to remove/reset the list also needs implementing. I might indeed let someone else handle that, I've metaphorically lost my mind hate-thinking at Android, Java, Dart, Flutter... I prefer Assembly/C/C++. At the moment I'm running some test code to make sure it behaves map-wise the way it should. I suspectputIfAbsent
doesn't do as I had hoped, so I may need to tamper that logic shortly.
I'd be happy to help out with UI issues. Looking forward to the PR!
I'd be happy to help out with UI issues. Looking forward to the PR!
Here is the initial Pull Request. See the notes. Edit: For everyone unfamiliar with coding for Android following the thread: This is just back-end work, I don't use Dart/Flutter front-ends, nor did I provide a way to access a list of certificates overridden. That should come easily to a front-end developer and you could theoretically have a final working solution today, depending on how much effort can be put into it. A simple menu in configuration/settings after login to edit overrides, a simple dialog with proper contextual messages/warnings on connect, and automatic "connection reattempt after decision" is all this needs to be a final working solution.
I use step-ca to provide an internal cert authority for services on my private (nebula based) mesh network. I install the root certificate to all the devices in the network, including my phone, to allow for apps like jellyfin to use TLS connections without issue. This works on all apps except finamp. It works on the official jellyfin app, for example.
If I understand this thread correctly, this is because the Dart language does not have an interface to check against user installed certificates on android? Is there an open issue for this upstream? I'd be happy to ping that thread as well.
I use step-ca to provide an internal cert authority for services on my private (nebula based) mesh network. I install the root certificate to all the devices in the network, including my phone, to allow for apps like jellyfin to use TLS connections without issue. This works on all apps except finamp. It works on the official jellyfin app, for example.
If I understand this thread correctly, this is because the Dart language does not have an interface to check against user installed certificates on android? Is there an open issue for this upstream? I'd be happy to ping that thread as well.
Check out (and build) the certificate-overrides
branch. You can try it.
Is any progress being made on this, especially for the FDroid version?
Is any progress being made on this, especially for the FDroid version?
Unfortunately not by me, I auto-patch bundled software and root my devices, I'm also porting phones to Linux (think Postmarket OS) to dump Android, so I'm out. :/
The Flutter app for Immich has recently added support for this, so we should be able to follow their approach. I've left a comment about it in #546. I don't use self-signed certs myself, so I'd appreciate someone with more experience in that regard to give it a go.
@OdinVex Finamp also runs on Linux now and I've heared of people using it on PostmarketOS/ARM. Just thought I'd let you know, in case you want to keep using it ^^
The Flutter app for Immich has recently added support for this, so we should be able to follow their approach. I've left a comment about it in #546. I don't use self-signed certs myself, so I'd appreciate someone with more experience in that regard to give it a go.
I looked into how they did it. It's the "will get your app banned from the Play Store if Google finds out" way. Google is strict about that API and specifically warns (threatens, actually) developers from doing that.
I guess we'll just wait a bit and see what happens to Immich then ^^
If they don't get removed, as a much more popular app than Finamp and a direct competitor to Google Photos, than it might be worth the risk :)
I guess we'll just wait a bit and see what happens to Immich then ^^ If they don't get removed, as a much more popular app than Finamp and a direct competitor to Google Photos, than it might be worth the risk :)
Originally Google would scan binaries to see if they attempted to override/hook/utilize that API but it's been a few years. The F-Droid version could get away with it no problem. I always tried to use F-Droid versions anyway when I was on Android.
I've set up a self-signed certificate on my Jellyfin server and installed it also as a trusted root CA on my devices. It works fine without security warnings on Chrome (both Windows and Android) and on Android apps, like official Jellyfin and Gelli, except Finamp. When I try to connect to my server in Finamp 0.5.1, I get
HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:359))
Certificate extensions: