Choose browser encryption algorithm for user authentication - authentication

I am working on authentication system that works only with public-private keys for authentication. No email, no phone.
I need to pick "proper" algorithms for user authentication and account recovery.
https://diafygi.github.io/webcrypto-examples/
user_id - public-key generated by user's browser during sign-in. Should be short and not include special chars. Will be used more as unique identifier for the user between different systems. Also used for account recovery. Could be for ex. last 20 bytes of the public address, as long as the chance of collisions is very low.
login_pub_key - generated by user`s browser. User will use the private key for authentication.
recovery_pub_key - generated by user's browser. User will use the private key together with user_id private key for for account recovery and to change login_pub_key.
Do you have any suggestions what would be suitable for these 3 cases?

Related

Storing API key

I am building a website that’s gonna have a pay system that works with the mollie API. In particularly the website needs to send users a payment link for their ordered products. To accomplish that mollie needs to authenticate with a api key. So I need to store the api key somewhere safely.
So my idea is to use AES Symmetric Cipher encryption when the admin registers his api key (CMS). With this encryption I need only one key to decrypt and encrypt the api key. I was thinking of using the plain text password of the admin as the key, because I don’t store this value (I hash the passwords) so it’s only available when then admin types his password. So when the admin wants to send a payment to an user the website will ask his password.
So my question is: Is this is a safe way of storing the api key?
Sorry for my bad English, it's not my native language.
First. API secrets and passwords have different lifecycles (key rotation & password change policies), and possibly different complexity requirements.
Second, The admin's plaintext password shouldn't be used for anything other than signing the admin in. Don't put all your eggs in one basket - you want to limit the scope of damage in case a secret gets compromised.
You would be better off just creating a separate secret for API key encryption/decryption, and storing it in some secret management e.g. Vault, AWS secrets, etc.
If you want to avoid storing the API key altogether, and you're fine with the admin just remembering it, then you can have the admin manually enter the secret, like a second password, but in any case it would be bad practice to couple it with the admin's sign-in password.

Handle user login using asymmetric cryptography

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.

how to store a password in webapp that needs to be passed in plain text to a third party?

I have a simple webapp which users login to access to a third party API that also require their personal credential in plain text username and password (no OAuth or anything). What's a proper, safe-ish, and straightforward way to store these third-party passwords so I can decrypt them to plain text when needed and minimise leakage of these passwords?
I'm thinking of just hardcoding GPG keys in to encrypt in webapp for storage and decrypt from another machine behind firewall when needed.
I don't think this is a GPG-specific problem. You could think of a scheme like the following (no need for public key crypto):
Generate a random password to encrypt the plaintext credentials you want to protect
Derive a key to protect this random password from the user's password
Encrypt the password from step 1 with the password from step 2
Now you can access the protected credentials after the user has logged in (since you know the password the user entered). When the user changes his password, you only have to re-encrypt the key from step 1 (in case you use this key in multiple places; so you can't miss one).
For step 2, you should use some (slow) key derivation function like PBKDF2. This makes sure that in case of a security breach, a simple dictionary attack on the encrypted credentials is not possible.

Network Security

Token cards display a number that changes periodically, perhaps every minute. Each such
device has a unique secret key. A human can prove possession of a particular such device by
entering the displayed number into a computer system. The computer system knows the
secret keys of each authorized device. How would you design such a device?
I believe this kind of authentication scheme is part of "two-factor authentication". In many popular 2FA solutions the user owns a small calculator-size device with a preconfigured PIN key. Upon entering the PIN, a One time password (OTP) is generated.
By entering the generated password, associated with his username, the user "proves" he has the device and knows the PIN code. Aladdin's safeword is such a device, popular in corporate/VPN/WifiPEAP environments.
It's also nowadays centralised and OTP are now often sent through SMS.
If you google around for the "How to implement two-factor authentication", you'll find numerous good articles. The topic is complex and involves many different technologies.
You can try this article for instance.
In the token device:
A stable clock with maximum deviation of 10s/year (can be done using quartz crystal oscillator), synchronized to UTC.
A public key stored individual to each device
Some random saltID, which also serves as the user identification value, so it should have reasonable length
A hash function
The number the token shows is generated by combining the saltID with the current time, hashing the value and encrypting it with the public key.
Upon login the authentication system reperforms the steps of the authentication token, minus of the public key encryption (i.e. it just computes the hash). The crypted hash is decrypted and compared to the calculated hash. If both match the token is accepted as valid.
The better authentication tokens have some numeric input, where the user can enter his PIN code, for protecting against loss or theft.

Suggestions on storing passwords in database

Here's the situation - its a bit different from the other database/password questions on StackOverflow.com
I've got two sets of users. One are the "primary" users. The others are the "secondary" users. Every one has a login/password to my site (say mysite.com - that isn't important).
Background: Primary users have access to a third site (say www.something.com/PrimaryUser1). Every secondary user "belongs" to a primary user and wants access to a subpart of that other site (say www.something.com/PrimaryUser1/SecondaryUser1).
At mysite.com, the primary users have to provide their credentials to me which they use to access www.something.com/PrimaryUser1, and they specify which "subparts" the secondary users of their choice get get access to.
Mysite.com helps manage the sub-access of the secondary users to the primary user's site. The secondary users can't "see" their primary user's password, but through my site, they can access the "subparts" of the other site - but ONLY to their restricted subpart.
In a crude way, I'm implementing OAuth (or something like that).
The question here is - how should I be storing the primary user's credentials to the other site? The key point here is that mysite.com uses these credentials to provide access to the secondary users, so it MUST be able to read it. However, I want to store it in such a way, that the primary users are reassured that I (as the site owner) cannot read their credentials.
I suppose this is more of a theoretical approach question. Is there anything in the world of cryptography that can help me with this?
Text added:
Since most ppl are completely missing the question, here's attempt #2 at explaining it.
PrimaryUser1 has a username/password to www.something.com/PrimaryUser1Site
He wishes to give sub-access to two people- SecondaryUser1 and SecondaryUser2 to the folders- www.something.com/PrimaryUser1Site/SecondaryUser1 and www.something.com/PrimaryUser1Site/SecondaryUser2
Mysite.com takes care of this sub-user management, so PrimaryUser1 goes there and provides his credentials to Mysite.com. MySite.com internally uses the credentials provided by PrimaryUser1 to give subusers limited access. Now, SecondaryUser1 and SecondaryUser2 can access their respective folders on www.something.com/PrimaryUser1Site through the MySite.com
NOW, the question arises, how should I store the credentials that PrimaryUser1 has provided?
First rule: Never, ever store passwords!
Second rule: Calculate a hash over password, with additional salt, and store this in your database.
Third rule: A username (uppercased) could be used as salt, but preferably add a little more as salt! (Some additional text, preferably something long.)
Fourth rule: It doesn't matter how secure a hashing algorithm is, they will all be hacked sooner or later. All it takes is time!
Fifth rule: The security of your site depends on the value of what's behind it. The more value the content has, the more likely that you'll be attacked!
Sixth rule: You will discover, sooner or later, that your site is hacked but not through a hacked password, but through a loophole somewhere else in your code. The biggest risk is expecting your site is secure now you've implemented some strong security.
Seventh rule: All security can be broken, all sites can get hacked, all your secrets can be discovered, if only people are willing to invest enough time to do so.
Security is an illusion but as long as no one breaks it, you can continue to dream on! Always be prepared for rough awakenings that will require you to rebuild your illusion again. (In other words, make regular backups! (Preferably daily.) Don't overwrite the backups of the last week and make sure you keep at least one backup of every week, just in case you discover your site was hacked months ago and all your backups ever since are infected!
Now, if you really need to store passwords, use a hash over username plus password. Then hash again with hash plus salt! Better yet, create a list of salts (just list of words) and whenever a new user account is created, pick a random salt word to use to hash his username plus password. Store the index of the salt with the user account so you know which one to use whenever he logs on again.
And:
Eight rule: Always use HTTPS! It's not as secure as most people thing but it does give a feeling of security to your users!Since you've added text, I'll add more answer.
Since you want user1 to grant temporary access to user 2, you'll need a secondary user table. (Or expand the user table with a parent user ID. Also add a timestamp to keep track of the account age. User 1 can create the credentials and this is done in the normal way. Just store a hash with combined username and salt. In this case, use the username of user 1 as additional salt! Just make sure you'll disable the user 2 account when user 1 logs off or when a certain amount of time has gone by. And allow user 1 to enable all accounts again that he created, so they can re-use an account instead of having to create new ones all the time.
Security isn't a matter that depend on primary or secondary users. In general, treat them the same way! Secondary users have an added bonus that you can use the primary account as additional salt. The rest of it has nothing to do with authentication any more. It's authorization that you're dealing with. And while authentication and authorization have a strong relationship, be aware that you should treat them as two different, stand-alone techniques.
When user 1 logs on, he's granted access to the primary site. When he grants access to user 2, user 2 gets a reduced set of roles. But this has nothing to do with storing user names or passwords. You just have an user-ID which happens to be member of certain roles, or groups. Or not, but those would be inaccessible.
They're both just users, one with more rights than the other.
It depends on the kind of authentication your primary site and the secondary site agree on. Is it forms authentication, HTTP Basic or HTTP Digest? If is forms or basic then you have no choice, you must store the password, so your only choice is to encrypt it. You cannot store a password hash as you must present the clear text during authentication for both forms and HTTP Basic. The problems that arise from storing the encrypted password are due to either incorrect use of cryptography (ie. you don't use an IV or salt or you don't use correctly a stream cipher), but more importantly you'll have key management problems (where to store the key used to encrypt the passwords and how to access it from a non-interactive service/demon).
If the 3rd party site accepts HTTP Digest then you're in better luck, you can store the HA1 hash part of the Digest hash (ie. MD5 of username:realm:password) because you can construct the Digest response starting straight from HA1.
I did not address how the user provision the secondary credentials (ie. how you get the secondary site username and password n the first place), I assume you have secured a protected channel (ie. HTTPS from client to your primary site).
BTW this assumes that the authentication occurs between your primary and secondary site and the secondary site content is tunneled through an HTTP request made to the primary site. If that's not the case and the secondary site is actually accessed straight from the browser, then the secondary site must support some sort of pre-authenticated token based authorization of third parties like OAuth. Relying on credential authentication and storing the credentials on the primary site when the credentials are actually needed by the browser has so many problems is not even worth talking about.
Have you thought about accepting OpenID like Stack Overflow does? That way you are not responsible for storing passwords at all.
There is only one way to do this, and it is probably too burdomesome for the users.
You could encrypt the users password with a public/private key, the user keeps their key so the password can be unencrypted only when the key is submitted back to your server. The only way to make this simple would to be to have some web browser plugins that auto submit the information.
And either way, you could always packet sniff the communication to/from the server so its still mostly pointless.
there has got be a better way to explain this :(
but if you just want to know how to store the passwords safely do this:
username:john, password:pass
key = '!!#ijs09789**&*';
md5(username.password.key);
when they login just check to see if md5(username.password.key) = is equal to the one in the db - you can also use sha1 and or any other encryption method.
http://us.php.net/md5 & http://us.php.net/sha1
Never store passwords in a database but store a salted and hashed version of every password.
Check this article if this is chinese for you.
If you want to store the password yourself the best apporach is to use a one-way hashing algorithm such as MD5 or SHA-1. The advantage of this approach is that you cannot derive the password from the hashed value.
Precisely which algorithm you choose depends the precise products you are using. Some front-end tools offer these functions, as do some database products. Otherwise you'll need a third-party library.
Edit
Secondary users ought to have their own passowrds. Why wouldn't they?
You're making it too complex. You need to stop trying to mix authentication and authorization.
What you want to do is establish credentials for everyone, not worrying at this point if they are "primary" or "secondary" users. Then on the main site, where you manage the users and the primary/secondary relationships, you can do the logic of which users are primary or secondary and store all that stuff in a table. You grant or deny whatever rights and sub-rights you wish to each secondary user whenever the primary users update their relationships with them. When they're done, you finally need to replicate the appropriate user credentials from the main site out to the secondary site(s).
Then when a secondary user wants to head to any site in your farm, they authenticate themselves only as themselves - they never impersonate the primary user! And they have only the rights you granted them when the primary users gave them "secondary" status.
--
OK, since you shot that solution down in the comment, consider this:
First, I doubt anything will be truly secure. You can always recover the secret if you monitor the users' activity.
Now, this is completely off the cuff, and I haven't cryptanalyzed it, but check into what is called a secret sharing scheme. Store the "effective" or "real" main-site primary user password as the shared secret. Use the salted hash of the password given by the primary user as one secret. Use the salted hash of the password given by the first secondary user as another secret, and so on for each additional secondary user. Don't store the salted hashes! Just store the salt and the protected shared secret.
When a user enters their password, you retrieve the protected shared secret, use the salt and hash of their password to produce the salted hash, decrypt the protected shared secret, and now you've got the original primary user password.