Context: I have a mobile app, and I don't have, and will not, implement a traditional authentication flow (email/pw, social login). Instead, I would like to leverage asymmetric key encryption.
Requirements: For the sake of simplicity, let's imagine a simple backend with one User model, which only has one field: favorite_number.
a user can CRUD a User model on the backend.
a user cannot CRUD another user's User model.
Potential solution:
Alice generates a private/public key pair on her mobile device. She keeps the private key securely on-device.
Alice makes a network request (let's say a RESTful POST request) to the backend, with the following payload:
{
"public_key": {Alice's public key},
"favorite_number": 42,
"signature": sign_with_private_key(42)
}
where sign_with_private_key(42) is the signature of the message 42, signed with Alice's private key.
The backend receives the above payload, verifies that the signature matches the public key and the favorite_number, and saves the following information in its DB (assume SQL below):
| public_key | favorite_number | signature |
| ---------- | --------------- | --------- |
| 0x... | 42 | 0x.. |
Alice wants to read her favorite number:
Alice sends GET /api/get_nonce?public_key={Alice's public key} to the backend
The backend looks in the DB the row with Alice's public key, and returns its signature column ONLY
Alice decrypts the signature with her local private key, it returns 42.
Bob wants to read Alice's favorite number, he calls the same endpoint GET /api/get_nonce?public_key={Alice's public key}, get's Alice's favorite_number signature, but cannot decrypt it.
Bob wants to modify Alice's favorite number, but cannot, because he can't compute the signature of the favorite_number message.
Caveats (which I can live with):
If Alice loses her phone or uninstalls the app, all her account information on the backend will be lost.
Additional assumptions:
The DB cannot be directly accessed by other party than the backend (and DB administrator) itself. (clarification request by #kelalaka). But that's independent of authentication.
Question: Is this authentication scheme viable? Do you see any big security loopholes?
This feels a bit over-complicated. If Alice has a keypair, then Alice can simply sign requests, and the signature is the authentication. There's no particular reason to sign individual pieces of data. Just sign the requests themselves. For example:
{
"request": {"message_id":123,"public_key":"...","favorite_number":42},
"signature": signature_of('{"message_id":123,"public_key":"...","favorite_number":42}')
}
It is critical that you sign everything that is part of the request.
Note that requests need to be single-use, otherwise this is not secure. By single-use, I mean that a timestamp should be in the request and the same request should not be useable more than once. You can also use a message counter (especially since you only have one device that can connect). So the server always rejects messages ids equal to or smaller than the last id sent for this user.
Your approach is vulnerable to reuse of the value upon another key. For example, I could reuse "42" and assign it to some other thing like "hated_number." Or I could replay this message and reset Alice's favorite number to 42 after she has changed it to something else. Signing the entire request is a much better approach and avoids a number of these problems (as long as a request can't be reused).
If Alice wishes to protect the data from the administrator, then she should encrypt the data with a symmetric key, but that's independent of authentication.
A simpler way to implement this, provided the transport is trusted, is to let Alice generate a random 256-bit identifier, and simply use that as the authentication. A 256-bit identifier will always be sufficiently sparse that it is unguessable (guessing the identifier is precisely the same as guessing an AES-256 key). With that, simply knowing the identifier is sufficient to authenticate a request. This only works if the transport is trusted, but that's the same as any static credential (username+password, token, etc). By a trusted transport, I mean HTTPS with pinned certs, for example, or any similarly encrypted and authenticated transport.
Related
There're plenty of sites, where you have to sign their 'sign in' message in order to get JWT from them. For example, https://www.cryptokitties.co uses such login system. It verifies the signature on the back-end and sends JWT back if address matches. It works good, but such approach disturbs me in the matter of security.
Assume, that someone has created absolutely identical to cryptokitties fake website. User hasn't noticed that domain is different, signs the same message ("To avoid digital cat burglars, sign below to authenticate with CryptoKitties") and at this point he already provided scammer with his signature and address, as message was the same, therefore it will work on original website. So basically you can loose your account by signing the same message on the completely different site. The saddest part, is that you cannot reset the private key, which means that your account has gone for good.
I'm not an expert, but it seems to me like a huge hole in security.
The solution I'm thinking about, is to encrypt the signature on the client before sending it on the back-end. With such approach, back-end will only send you a JWT if you've signed a message on our front-end. So, firstly back-end decrypts the signature and then verifies the message and address. It will skip signatures which were created on other sites as the decryption will fail.
So far we eliminated fake websites problem. But there is another one: attacker can intercept an already encrypted signature and use it on our site. And once again there is no way to reset the signature, it'll remain the same. So what I came up with is, signature must be disposable, it can be used only once. Before signing a message client requests from the back-end special random number linked with according wallet. Based on this number we build signature message like this: "To avoid digital cat burglars, sign below to authenticate with CryptoKitties #564324". Firstly, back-end decrypts the signature, verifies the address and then checks whether specified random number exists in database. Once login is succeeded, the random number is deleted from the database. Now, even if user looses his signature, it can't be used by attacker, because it's already expired.
What do you think? Does described approach make sense?
You have the right idea with "signature must be disposable". The concept is called a nonce (a value used to protect private communications by preventing replay attacks).
Your following logic is correct as well, except that you don't need to delete the nonce from the database, but rather rotate it. I.e. update the value to a new pseudo-random (or at least hard to guess) value.
So I have a document shared between two or more users. Call them Alice and Bob.
When editing this document, Alice is signed in using OAuth with office 365 or google gsuite; I'll call that an identity provider.
When I pass this document to Bob, I want to be able for Bob to have confidence that the content written by Alice was indeed written by someone with the ability to sign in the identity provider as Alice.
The obvious way to do this is for Alice to digitally sign the changes in the document with a public/private key pair, and then connect the public key to her own identity.
This will require that Bob can get at that public part of the key through a way they can reasonably verify required that Alice put that public key there.
Also, I want the file's current location/storage/transmission to not be required to prove the identity of Alice in any way. And, ideally, I'd like Alice to be able to authenticate, disconnect from the internet, and continue to be able to make provably-authored edits on her document.
I'm afraid I'm reinventing the wheel, but I cannot find any evidence that there are pre-existing APIs for doing this. This seems like a really basic set of operations; being able to sign data with identity, and verify it was that identity that signed it. I was somewhat surprised when I couldn't find an API to do this.
Embedding a link to a shared document that Alice has on her cloud storage, and having Bob go and fetch it to verify the signature, is one thing I'm considering; is there a way to have a stable URL with both of those storage providers that can be traced back to being connected to Alice?
Is there a better approach?
Alice must get document signing certificate separately from the office 365 or gsuite. It is possible to get simple and cheap certificate that shows that this e-mail address control has been verified.
If the private key is on the HSM like Smart Card or USB token then it is possible to get eIDAS approved or Adobe Trusted list CA signed certificate and signature validation is relatively easy.
It is also possible to setup your own CA and in this case you need to implement signature validation as well and make sure your own CA is trusted by Bob
Is it possible to implement a login protocol with asymetric cryptography instead of the hashed password method?
For example, while creating an account, the client generates a private/public key pair from a hash of the username and password. The public key is then sent to the server with the username, and the server stores the username and the public key. When the user wants to login, he enters his password, the client regenerates the private key, signs a nonce with it, and sends the signed message to the server. The server is then able to authenticate the user as he knows the public key associated with the username.
Is there any flaws in this protocol?
And what would be the advantages over storing the password hash?
There might be a serious flaw with the authentication, yes, depending on the implementation. If Bob is the server and Alice is the client, with Mallory a malicious eavesdropper:
If Alice generates a random number, concatenates this with her username, encrypts with her private key and sends to server. Server decrypts and verifies with Alice's public key. Without the server saving the random number, this is susceptible to replay attacks - Mallory could just listen in, save the blocks that Alice sends to the server and just replay them later. Without saving them, the server would be none the wiser.
To protect the server against this, the server would have to generate the random number. It would also need to be a secure random number, otherwise Mallory could predict, or at least guess what the next number will be.
If Mallory could intercept messages, then he can purport to be Alice - he intercepts all communications and just relays them, even if the server generates the random number.
Alice and Bob both need to be able to prove that it was the other who has cheated. They also need to be able to detect tampering from Mallory - the protocol needs some extra layers to ensure authenticity of the messages.
There is research going into this at the moment, but as far as I know, it is very difficult to authenticate a user without a trusted certificate authority also being used: public keys can be known by all, but any attacker can swap their own public key for that of another without detection, unless there is trust established through a certificate authority.
I need some advices on how to secure my application:
I have a REST service, using Spring MVC 3
I have my client application, using Ext GWT 2.2
Users credentials are available on the server side only.
SSL available
REST services should only be used by authentificated users.
I have read about HTTP Digest , token based authorization, oAuth etc, but I need some clarification and advices on how to secure my application, and which methods are the best in my case.
here is the methodology we created for our applications, works very well, and is very secure.
this is a very conceptual explanation, there is a lot of code that backs this up, FYI
When user authenticates or creates account, the server returns an x.509 certificate, base64 encoded, that is unique to for the user. The server stores a copy.
Everytime the client needs to access the REST API, client creates a JSON string comprised of the following.
The Users Unique ID (UserID)
A GUID or UUID, that guarantees this call is unique,(CallID) (protects against replay attacks)
A Dictionary (collection of Key/Value) of each parameter of the rest call
we then encrypt that string with the x.509 public key, and encode it back to base64 string, and take this encrypted value and add the UserID to a json object we call the token.
we then put the token into header of each call, and call it something like: X-Auth-UserToken
On every call the server takes the token, looks up the users certificate based on the userID, then verifies that the encrypted part of the token can be decrypted with the private key that the server holds for the user.
once decrypted, the server takes the CallID and verifies that it is unique, against its own calllog db.
if it checks out, the user is authenticated.
once the user is authenticated, you can apply your own authorization rules based on the users uniqueID.
of course, all the above is over SSL.
let me know if you need me to drill down on any parts.
this is a clueluess question, but what does the Socialist Millionaire Protocol, which is typically used in conjunction with OTR-Messaging, that "conventional" Challenge-Response Mechanisms like CHAP can't do?
http://en.wikipedia.org/wiki/Socialist_millionaire
http://en.wikipedia.org/wiki/Challenge-handshake_authentication_protocol
PS: Can someone consider adding the tag "OTR"?
A standard challenge response system works like this:
Bob, the server, sends Alice a random challenge number.
Alice performs a cryptographic operation on the challenge using her secret.
Alice sends the result to Bob.
Bob performs the same operation on the challenge with his secret.
If the result of this calculation matches the response Alice sent him, then Alice must have used the same secret.
The problem with this scheme is that an eavesdropper who gets the challenge and the response can use their supercomputer to bruteforce the secret. They can perform the cryptographic operation repeatedly with many secrets and if they find a secret that produces the observed response they know that that is the shared secret between Alice and Bob.
If the secret is a 128 bit key or a very strong passphrase then bruteforcing the secret will take a very long time and will be impractical but for small secrets like numeric pins or normal passwords bruteforcing is a very real threat.
The socialist millionaire's protocol serves the same purpose but it doesen't reveal any information about the secret. An eavesdropper can't use the messages sent back and forth to learn anything about the secret even if they had an infinitely powerful computer. Even if the attacker pretends to be Bob and can send any messages he wants back to Alice, they still can't get any information about the secret other than whether the guess they made was correct.
In the CHAP protocol the client just proves his identity through showing that he has knowledge of the key. This could also be done with asymmetric cipher. The client just has to encrypt randomly generated challenge and the serve has be able to verify the content.
The Socialist millionaire protocol tells both entities that they have either used to same value or a different value. This could also be used as a login protocol. It will then offer mutual authentication.