0

I'm currently trying to come up with an authentication process for an Android app, that talks with web backend using REST. At the moment the communication is secured by TLS (with cert pinning) and auth tokens - former makes the client trust the server, latter allows client to make calls to the server's API. Auth tokens are given to the client if a user registered in the system successfully authenticates with login/password within the app. The user doesn't have to re-authenticate between the runs of the app, unless they manually choose to log out at some point.

It's easy to see that in a scenario where user gets his device stolen, the attacker can easily impersonate them, so it would be nice to introduce an additional authentication measure for security-critical operations. For UX-related reasons, I cannot ask the user to re-authenticate with login/password. I can however use a typing-friendly secret, like 6 digit PIN, and a limited number of authentication attempts.

My first idea was based on Android-specific cryptography (Keystore). Generate an ECDSA or RSA key on the device, then register the public key in backend's database. When security-critical operation comes, do a challenge-response, where client proves it has the private key corresponding to the registered public one. Unfortunately, Android platform doesn't allow the developer to have per-application access control to the keys stored on the device. Access control to Android Keystore is based on system-wide credentials used to unlock the device (pattern/pin/biometrics), and unfortunately I cannot rely on them. I also cannot safely implement my own PIN check within app, because that can be bypassed with a debugger.

My second idea is to authenticate user's PIN with SRP protocol, with backend keeping track of authentication attempts. From what I have read, it's a widely implemented solution in the industry. However, it seems to me that it has been designed with different things in mind, so I'm not sure how well it would fit my purpose. For example, in the first step of the protocol, server returns salt to the client. I assume that's because the 'client' in SRP can be a web browser, and user can use any browser from any device, so you can't really expect the client to have anything except his password. In my scenario, mobile app is supposed to be an entity within the system and one of the user's authentication factors (something the user has - the auth token). So I might as well store the salt on the device, especially since in case of server's database leak, when all the verifiers and salt values get public, 6 digit PINs can be easily dictionarized.

The other thing is, I already have TLS as a measure to authenticate the server, and I don't need the shared key for much, since the session effectively ends when the server is convinced the user entered proper PIN.

I would like to ask, if you think the SRP protocol is a good solution to my problem, what should I take into account, and if there are better alternatives.

  • Can you elaborate on why system-wide credentials cannot be relied on by you? Would you assume that if a mobile device is stolen, then the PIN/biometrics will be used by the thief as well? Many banking and health applications utilize this mechanism for such elevations (even fast authentication by storing the refresh token under this mechanism). As for SRP: I would read this article (https://blog.cryptographyengineering.com/should-you-use-srp/) from 2018. – Harel M Aug 30 '22 at 15:33
  • Why do want to store the salt on the device?.. – Sir Muffington Aug 30 '22 at 15:55
  • ***"Unfortunately, Android platform doesn't allow the developer to have per-application access control to the keys."*** Of course it does. [Android keystore system](https://developer.android.com/training/articles/keystore) has everything you need. Use [Require user authentication for key use](https://developer.android.com/training/articles/keystore#UserAuthentication) to authenticate the user in-app for critical operations. Password Managers use this feature all the time. – defalt Aug 30 '22 at 17:09
  • @HarelM not sure about other banks, but my banking app allows using phone-based biometrics for authentication, but only for limited subset of operations. For anything else I have to use PIN code, and this is not the same PIN as for unlocking the device - it's app specific and set in the app's UI. As for the link, I'm familiar with this article, and endorsement of OPAQUE instead of SRP, but the former isn't yet standardized and has no implementations in crypto libraries (I would rather avoid implementing such things from scratch). – barti90 Aug 30 '22 at 19:53
  • @defalt I'm not aware of android API calls that will allow me to define app-specific PIN for using a key in a Keystore. I can request PIN authentication before key use by the application, but this is PIN code used to unlock the device. – barti90 Aug 30 '22 at 19:56
  • @SirMuffington I don't necessarily want to. I just don't see much of a purpose in storing it on the server if I don't have to - server database leak will result in pretty much all credentials getting public. – barti90 Aug 30 '22 at 19:58
  • Why can't you use the PIN that unlocks the device? Only the owner of that device will pass that authentication. – defalt Aug 31 '22 at 10:23
  • @defalt threat model assumes that the attacker can bypass the screen unlock (rooted phone, running the app in debug mode, etc.). I'm also not sure if I can force the user to use at least 6 digits for his device PIN – barti90 Aug 31 '22 at 11:41
  • With root, the user will be able to bypass any security that protects critical security operations. Use hardware backed SafetyNet attestation to prevent the app from running on rooted device. By design, screen lock authentication cannot be bypassed on non-rooted devices. – defalt Aug 31 '22 at 12:15

0 Answers0