Authentication & Security

Check branches to get code for certian level

Level 1 ( Register Users )

  • simply let user register with username and password.
  • stored username and password in database without any encryption ( vulnerable ).

level 2 ( Data Encryption )

Why Encryption❓ Any one who can access the database can get user passwords directly. 🙂🥲

encryption image

  • Save encrypted password in database instead saving them as it is.
  • mongoose-encryption package is used for encryption docs.
  • simply plugged in the package docs.

mongoose plugins: By adding plugins to mongoose Schema we can extend their functionality.

require("dotenv").config();
const encrypt = require("mongoose-encryption");

const userSchema = mongoose.Schema({
  email: String,
  password: String,
});

// keep the secret in the .env file
const secret = process.env.SECRET;

// plugin the mongoose-encryption package in Schema
userSchema.plugin(encrypt, { secret: secret, encryptedFields: ["password"] });

//plugin package before creating collection or model
const User = new mongoose.model("User", userSchema);

level 3 ( Hashing Passwords )

Why Hashing❓
Encrypted data is secure, but can be decrypted, anyone with key and cipher method can get actual data or password.

Hashing comes in the picture

hash functions are complicated MATH FUNCTIONS which can hash any input in miliseconds, but It is almost impossible to undo hashing or get back plain text...

hashing image

  • Using hash function Hash the user password and store it in database, user is the only perosn who knows the actual password.
  • Use same hash function to authenticate user.
  • MD5 hash function. Widely used hash function, produce a 128-bit hash value docs.
var md5 = require('md5');

// save hashed password in database, while registration
password: md5(req.body.password),

// Use same hash function for authentication, while login
const password = md5(req.body.password);

level 4 ( Salting & Hashing with bcrypt )

Why not just Hashing❓

  1. If password is not strong then there are multiple ways it can get hacked like Dictionary attack.
  2. People have created Hash tables for commonly used passwords.
  3. If multiple users have same password then their hashed values are also be same.

Salting❓ A salt is a random string that makes the hash unpredictable.
Before hasing add salt to user password & store hashed password and salt in database.

  1. It is impossible to hack.
  2. Very difficult to find these hash values in hash tables on internet.
  3. Now even users with same password endup having different hash values.

salting image

Salt Rounds❓God level secure

  1. First Round : Generate hash password using User password and salt.
  2. Further Rounds : Generate new hash password using previously generated hashed password and same salt.

salting Rounds image

bcrypt❓ Bcrypt is a popular and trusted method for salt and hashing passwords.

  • bcrypt package from npm is all we need docs.
  • There are two different techniques in documentation
  1. Technique 1 (generate a salt and hash on separate function calls).
  2. Technique 2 (auto-gen a salt and hash). used below.
const bcrypt = require("bcrypt");
const saltRounds = 10;

// While registration use hash method
bcrypt.hash(req.body.password, saltRounds, function (err, hash) {
  // Store hash in your password DB.

  const password = hash; // Generated by bcrypt, js
});

// While authenticate or login use compare method
bcrypt.compare(req.body.password, password_from_db, function (err, result) {
  // result == true || false
});

level 5 ( Cookies & Session )

Cookies are used to store information about the user's activity on the website, and this information is then sent back to the website or server each time the user returns. what is use of cookies...

1. Session Management

Cookies can be used to manage user sessions on a website. We can store session IDs or tokens inside cookie, that allow the server to identify and authenticate users.

2. Personalization:

Cookies can remember user preferences and settings, such as language preferences or layout preferences, to provide a personalized browsing experience.

3. Authentication:

Cookies can be used for user authentication, allowing users to stay logged in between visits to a website without having to re-enter their credentials each time.

4. Shopping Carts:

E-commerce websites use cookies to store the contents of a user's shopping cart, making it possible for users to add items to their cart and continue shopping across different pages or sessions.

5. Ad Targeting:

Third-party cookies, often used by advertisers, track users' online behavior across multiple websites to deliver targeted ads based on their interests and browsing history.

Cookies can be categorized into two main types:

Session Cookies:

These cookies are temporary and are deleted from the user's device when they close their web browser. They are typically used for session management and are not stored on the user's device long-term.

Persistent Cookies:

Persistent cookies are stored on the user's device for a specified duration, even after the browser is closed. They are often used for purposes like remembering user preferences or tracking long-term behavior.

Packages used in project for cookies and session are

  1. passport docs.
  2. express-session docs.
  3. passport-local-mongoose docs.

And salting & hashing will be taken care by passport-local-mongoose 🙃 .

const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");

// Mount the session middleware function
//from express-session
app.use(
  session({
    secret: "ThisIsMySecret",
    resave: false,
    saveUninitialized: false,
  })
);

// Mount the passport middleware function
// from passport docs.
app.use(passport.initialize());
app.use(passport.session());

// db
const userSchema = mongoose.Schema({
  email: String,
  password: String,
});

// mongoose plugin for passport package
// from passport-local-mongoose
userSchema.plugin(passportLocalMongoose);

// configuration
// from passport-local-mongoose
passport.use(User.createStrategy());

passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

// register user store session cookie and store hashed pass in db
app.post("/register", async function (req, res) {
  // from passport-local-mongoose
  User.register(
    { username: req.body.username },
    req.body.password,
    function (err, user) {
      if (err) {
        console.log(err);
        res.redirect("/register");
      } else {
        passport.authenticate("local")(req, res, function () {
          res.redirect("/secrets");
        });
      }
    }
  );
});

// authenticate user
app.post("/login", async function (req, res) {
  const user = new User({
    username: req.body.username,
    password: req.body.password,
  });
  // from passport docs
  req.login(user, function (err) {
    if (err) {
      console.log(err);
      res.redirect("/login");
    } else {
      passport.authenticate("local")(req, res, function () {
        res.redirect("/secrets");
      });
    }
  });
});

// logout and terminate seesion
app.get("/logout", function (req, res) {
  // from passport docs
  req.logout(function (err) {
    if (err) {
      return next(err);
    }
    res.redirect("/");
  });
});