Securets

project / February 14th, 2021

Securets Home Page

Securets Web AppGitHub

Background

Securets is a basic and minimalist version of the Whisper app, which allows users to submit their secrets anonymously and can be viewed by all users of the app. The website has a home page with two buttons that allow you to either register a new account or log in with an existing one. Once the user is logged in and has been authenticated, they are able to view all the secrets that have been submitted to date and can submit one themselves.

Securets Secrets Page

This also serves as the project for the Authentication and Security module from the Complete Web Development 2021 Bootcamp.

Purpose

To learn about authentication!

Why? When creating web apps where users generate data, those pieces of data must be associated with each user. To do this, each user should be able to create an account with a username and password. This is essentially an ID card to uniquely identify each user on a database and save the data they generate when logged in. With an account, users will be able to log into websites and access those private pieces of data.

Another reason for adding authentication to a web app is to restrict access to certain areas of the website, depending on the login status of the user and their credentials.

Concepts and Tools Used

  • Authentication and Security

  • Encrypting, Salting and Hashing Passwords

  • Environment variables and .gitignore to hide sensitive information

  • Passport.js, OAuth 2.0, and third party sign-in

  • Node.js

  • Express.js

  • EJS

  • MongoDB and Mongoose

  • Robo 3T

Scope and Modifications Made

The bootcamp has provided starting files for the stylesheets and EJS templates for the home, register, and login pages. This enabled me to narrow my focus down to simply adding authentication and security and coding the EJS templates for the secrets and submit pages.

Since this project covered such a complex and unfamiliar topic, I did not deviate much from the original project for most of the module, as going through the six levels of security required deleting code from the previous steps and writing new code in its place.

One modification I did make was add an option to register and login with an existing Twitter account, in addition to the local sign-in and Google sign-in.

Process

The difficult part of authentication arises from how secure one wants to make their website. Therefore this project and module was in arranged in a manner so that the six levels of security would be thoroughly examined, starting out as basic tasks and gradually increasing in complexity:

  • Level 1: The basics. This involves setting up account creation for users and enabling them to register with a username (an email in this case) and password. A database of users is created using MongoDB and Mongoose and the user information is stored here after it is submitted through the form on the register page. In the login page, the user enters the email and password they used to create the account and the database is checked for a user with the credentials that have been entered. A problem with level 1 security is that user passwords can be seen in plain text, which is especially problematic if the database is hacked and a user reuses the same passwords.

Securets Register Page
  • Level 2: Database encryption. Encryption on user passwords in our database is implemented using the "mongoose-encryption" NPM library. "mongoose-encryption" is added as a plugin to our database schema, and then a long string called a "secret" is defined and used to encrypt the password field when saved in the database. When logging in, "mongoose-encrypt" will decrypt the password from the database and compare it to the entered password to determine if the user can log in. Although the encrypted password is now a long binary string that is hard to guess, the decrypted password can still be logged in the console. This can be problematic if someone has hacked your website, as they can find your "secret" and use it to decrypt all of your passwords. As long as the plain text version of your user passwords can be recovered, there will always be a security issue. This can be remedied using environment variables and gitignore to keep secrets safe.

  • Level 3: Hashing passwords. At this point, the biggest flaw in the level 2 authentication method is the fact that an encryption key is needed to encrypt and decrypt passwords. Even if the encryption key is hidden in environment variables, one can hack into the database and find it if they are motivated enough. To address this weakness (the need for the encryption key), a hash function is applied to the passwords using the md5 library to turn it into a hash. This eliminates the need to use an encryption key and decrypt the password back into plain text, as we simply hash the entered password from a login attempt and compare it to the hash stored in the database - the only person who would know the password in plain text is the user themselves.

  • Level 4: Salting and hashing passwords with bcrypt. When a database of users is hacked, they may notice that multiple usernames have identical hashes - because the same password always turns into the same hash. What the hacker can do is construct an md5 hash table or search up an existing one, which contains the hashes of most commonly used passwords (eg. 123456, qwerty, password, 111111) and cross-reference it to each hash in the database to figure out the password. To create a hash that is difficult to match to one in a hash table, the password must be a strong one, with password length being the most important factor. To make common passwords more secure, the password can be salted using the bcrypt NPM package before hashing it - this involves generating a random set of characters (the salt) and combining it with the original password to increase its length before applying the hash function. Therefore if there are multiple users with the same common password, the hashes for each will all be different and unsearchable since the salt added to each password is randomly generated each time. Additionally, bcrypt also has a option called salt rounds - the number of rounds you're going to salt and hash your password. The more rounds done, the more secure your hash is.

  • Level 5: Using Passport.js to add cookies and sessions and implement local sign-in. This allows us to authenticate users using a local strategy (a username and password that wasn't created using a third-party application like Google or Twitter). So once the user has successfully registered or logged in using the right credentials, a cookie is sent to tell the browser to hold onto that cookie, because the cookie has a few pieces of info that tells our server about the user - namely that they are authorized to view any of the pages that require authentication. If the user logs in successfully or is already logged in, they will be redirected to the secrets page. If not logged in, they will be redirected to the login page.

  • Level 6: OAuth 2.0 and implementing third party sign-in. In addition to authentication using a local strategy, we can authenticate using other services like Google, Twitter, LinkedIn and Facebook. By using OAuth, we're able to request access to specific pieces of info on these third party websites such as friends, emails, or contacts on Gmail. In our case, because we want to level up the security of our authentication, a big benefit of third-party sign in involves delegating the task of managing passwords securely to companies like Facebook and Google who are able to use their vast resources to implement high levels of security for authentication on their website. So when a user wants to log into Securets with their Google account, they will be asked to log in on Google, and Google will then authenticate them using their own secure methods. Once done, Google returns a message indicating the user is authenticated and is a real Google user with a correct username and password - at which point Securets authenticates them as well. In addition to Google, I also implemented sign-in with Twitter.

Securets Third-Party Authentication

After going through these levels of increasing security, the app functionality is then completed by enabling the user to submit a secret into the database, and then iterating through the list of users in the database and extracting the secret that each user has submitted in order to display it on the secrets page.

Securets Submit Page

Outcome and Takeaways

This was a very difficult yet rewarding module, as I learned the process of building a website with poor security to one that is more consistent with industry standards of good website security. Through examining the six security levels step-by-step, I gained a deep insight into the various security vulnerabilities that each level presented that I will be aware of when signing up for websites or creating websites that requires logging in users.

Possible Improvements Going Forward

With extra time, I would like to add more third party sign-in options and learn more about each of their respective implementations.

I would also like to experiment with potentially allowing registered users to have more than one submitted secret displayed on the secrets page, instead of having just a user's latest submitted secret be the only one shown. However, this idea also has its drawbacks as users can spam the secrets page with multiple secrets. The collection of secrets would be less interesting if the majority of them were seemingly submitted from a minority of users!


External Links