Let’s continue our journey. I hope you’ll are all clear with previous lessons. Today I need to discuss another security mechanism. That is CSRF.

CSRF => Cross site request Forgery

Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they're currently authenticated. It can abuse user sessions and trick users in the application to execute malicious codes.

How?

There can be fake site identical to your site and in there and also there can be a link to your site ( like Post request that executes money transfer)
(user can inform this fake site by email.)

so, we need CSRF protection.
install- > npm install --save csurf

Need to add a token for every request (Mostly on sensitive ones) Any non-get request > this package searches for the existence of CSRF token in the request body (passed by views)

setup -> in app.js
import csurf->
const csrf = require("csurf");


After the session created (app.use(session{})) add these lines
const csurfProtection = csrf();
app.use(csurfProtection);

Then we need to add a field of csrf in the getmethod-> get sends the csrf (ex ->get login page)

exports.getLogin = (req, res, next) => {
  Product.find()
    .then((products) => {
      res.render("shop/index", {
        prods: products,
       //pass the token as in this field
        csrfToken: req.csrfToken(),
        isAuthenticated: req.session.isLoggedIn,
      });
    })
    .catch((err) => {
      console.log(err);
    });
};

in the view -> particular post request -> we need to pass back the csurf  (ex -> post data login page)

<form action="/login" method="post">
        // <input type="text"  name="email" />
        // <input type="text"  pass="password" />

          <input type="hidden" value="<%= csrfToken%>" name="_csrf" />
//with the get request this will come and when sending post request we need to pass it back

          <!-- name is important -> should be named as _csrf -->

          <button class="main-header__item" type="submit">Login</button>
        </form>


If the csrf token is invalid  -> it gives Forbidden Error: invalid csrf token
                             is valid      -> login successful

But adding these csrfToken: req.csrfToken() and isAuthenticated: req.session.isLoggedIn for every page we render is much more difficult.


The easy way:-

tell express js -> we have some data should be included in every render view.
for that -> need a special feture of express -> res.locals

in App.js
before all other routs middlewares (admin , shops etc..)

app.use((req, res, next) => {
  res.locals.isAuthenticated = req.session.isLoggedIn;
  res.locals.csrfToken = req.csrfToken();
  next();
});

now remove->
exports.getLogin = (req, res, next) => {
  console.log(req.session.isLoggedIn);

  res.render("auth/login", {
    pageTitle: "Login Page",
    active: "login",
    /*  isAuthenticated: req.session.isLoggedIn,    
        csrfToken: req.csrfToken(),
        these two now can be removed    */
  });
};

also you need to add
<input type="hidden" value="<%= csrfToken%>" name="_csrf" />

for every input form (that is a little bit of work though :)

Bonus -> Handling error messages.

store some data before we redirect => we can use sessions. We use sessions to store error messages temporally.

install-package -> flash
npm install --save connect-flash

1st=> initiate in App.js

import ->
const flash = require("connect-flash");

//register flash after the setting up the session (as csrf)

app.use(flash());


2nd=> when ever redirection happen in controllers->


I - setting the message

in postLogin->

req.flash("error ", "Invalid Email or Password...!!!");
        //use a key pair
        return res.redirect("/login");

II - sending the message

in getLogin ->

  exports.getLogin = (req, res, next) => {
  console.log(req.session.isLoggedIn);

  res.render("auth/login", {
    pageTitle: "Login Page",
    active: "login",
    errorMessage : req.flash('error')  // pull that entered msg by key
  });
};


III - viewing/displaying the error message

in view.js
we can show the error message

<div><%= errorMessage%></div>