5

I need help to authenticate users with user credentials.

We are using Angular 5 as a front-end & need to store the user's email and password if the user checks on Remember Me. Then autofill user credentials after logout and refreshing the browser.

There are several ways to store user credentials (Cookies, Local Storage, Session Storage, IndexedDB, WebSQL). but these all are not secure.

we thought about storing user credentials in localStorage by encrypting it, but anyone can decrypt it so, this way is not secure.

Our targeted browser includes Internet Explorer, MS Edge, Safari, Google Chrome, Opera, Mozilla Firefox.

How can we achieve client-side web storage using JavaScript?

schroeder
  • 123,438
  • 55
  • 284
  • 319
Parth
  • 153
  • 1
  • 6
  • 1
    A standard exists what you want [Web Authentication: An API for accessing Public Key Credentials](https://w3c.github.io/webauthn/) ... also explained more easy -> https://webauthn.guide/ .. i believe the browser support are the modern Firefox, Edge and Google chrome and thats about it.. – Raymond Nijland Oct 04 '19 at 14:56
  • 1
    .. the other option which is less userfriendly is using WebCrypto API in javascript and a server side code library to sign client ssl certifications which could be used to verify the user.. The userfriendly part is that a user needs to install the certificate by hand...in the past there was a html 5 tag `` which did the same it's most likely now [removed](https://security.stackexchange.com/questions/106257/alternatives-to-htmls-deprecated-keygen-for-client-certs) in most browsers... – Raymond Nijland Oct 04 '19 at 15:06
  • This is normally not how "remember me" functionality works. Normally, "remember me" either gives you a session that is valid for a longer time, or another token that can be exchanged for a valid session. This way, there is no need to remember the password, but only to remember the authentication token. – Sjoerd Apr 16 '21 at 13:34
  • Similar to https://security.stackexchange.com/questions/248093/imap-credentials-in-web-browser-app-how-to-use-securely/248108#248108 – mti2935 Apr 16 '21 at 17:48

2 Answers2

5

Anything stored client side (and not encrypted) can be seen and/or modified by the user.

The usual way of implementing a "Remember Me" functionality is to set a cookie with an encrypted username, sent from the server.

The server will encrypt the username with a secret key, known only to the server, and set a cookie with that value. When the server later receives that cookie, it can try to decrypt it, and if successful, log the user in. This cannot be tampered with by the user, as they do not know the secret key.

Chris Murray
  • 1,275
  • 11
  • 17
  • but this will autofill the data when the user came back after the logout. – Parth Oct 04 '19 at 10:48
  • 2
    Why would you want to autofill the login data? With the above method, you can skip the login stage altogether and go straight to a logged in user. – Chris Murray Oct 04 '19 at 11:01
  • The Functionality I want , After Logout when user come back to that login page all that users data will be auto-filled. – Parth Oct 04 '19 at 11:03
  • 2
    There is no way to do this securely on the client side. If you have all the information required to decrypt the details, so does any user local to the machine. You are trying to implement a password manager, for a single site, purely in JS. It's not possible, or useful. – Chris Murray Oct 04 '19 at 11:22
  • Silly question, but I want to ask how facebook & amazon does that remember me functionality? – Parth Oct 04 '19 at 11:26
  • 2
    They do it as I described above. A secret sent from the server, that can later be re-verified and log the user in. At no time is the username/password stored anywhere on the client's machine. – Chris Murray Oct 04 '19 at 11:30
  • 2
    You absolutely do *not* want to use an encrypted username as the remember-me value on the cookie, because that means that the cookie value is tied to the username. As a result, it's not possible to un-remember a user. If an attacker steals the encrypted username from the cookie, the system will remember them forever with no ability to kick them out. It's a very bad way to implement such a system. – Conor Mancone Apr 22 '21 at 19:02
  • 1
    Now, you *could* use a per-user key that you can rotate when needed, but it's much easier to just use a long, random string (aka a session token) attached to the user and store that in the cookie. Then you can change it, or even have multiple ones for different devices. – Conor Mancone Apr 22 '21 at 19:02
0

If your storing any data client-side, it is not secure and can be easily accessed by the user. One way of resolving this issue is by encrypting and decrypting your user's data. When encrypting the user's data, nobody will be able to access it because it needs to be decrypted using the secret key that you used to encrypt it. You can hide this secret key in many ways, though one way you can hide it is by getting the secret key via an environment variable (dotenv).

Once you access your secret key, you can use CryptoJS to encrypt and decrypt your data. Here is an example:

var myKey = process.env.mySuperSecretEncryptionKey

var encrypted = CryptoJS.AES.encrypt("TheUsersPassword123", myKey);

console.log("Your encrypted password is " + encrypted)

var decrypted = CryptoJS.AES.decrypt(encrypted, myKey);
//TheUsersPassword123

console.log("Your decrypted password is " + decrypted)

Using the following process will ensure that you and your server can access the user's data, but nobody else can because they need your secret key!

  • 1
    welcome and thanks for taking the time to provide an answer - the prob with this is that it doesn't show the use of any per-user salt or iv, nor any h/mac or tag to verify the ciphertext hasn't been tampered with, nor any time-bomb/ some other limiter to prevent replay attacks with a stolen cookie ... and i'll posit that a poor choice of server-side secret with default library params will fall quickly in the face of gpu-forcing ... but other than that it's all good! `:)` .. i challenge you to complete your example while sticking to the choice of the `crypto.js` library in `nodejs` – brynk Jun 20 '22 at 04:00
  • How does this approach solve the problem of "anyone could decrypt it", as mentioned in the OP? I could simply use your code and get the key and decrypt everything on the client. – schroeder Jun 20 '22 at 08:29
  • How would you get the key, if it is an environment variable? – BrianWalczak Jun 20 '22 at 18:27
  • if `mykey` is weakly composed then a user could gpu-force the ciphertext entrusted to them in `encrypted` (it seems to me that this would be the cornerstone of a more sophisticated attack), which is why a strong passphrase in the env var is important - some light reading to consider: [`EvpKDF.compute`](https://github.com/brix/crypto-js/blob/develop/src/evpkdf.js#L55); JWT/JWA spec, [s5 Cryptographic Algorithms for Content Encryption](https://datatracker.ietf.org/doc/html/rfc7518#section-5); [AWS sigv4 (as a kdf)](https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html) – brynk Jun 21 '22 at 22:12