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>

0 Comments