Vict E-commerce: Adding Basic Security

Vict E-commerce: Adding Basic Security
Photo by Scott Webb / Unsplash

Researching Security Options

In my previous blog Vict E-commerce: Setting Up Shop we went over setting things up for working collaboratively between myself & Jamil, as well as database management for merchants, products, & storefronts. In this blog, I go over what we learned about JWT vs sessions and how we implemented sessions. If you would like to read about the changes Jamil is doing check out his site: jaml.co

Originally we thought to do JsonWebTokens (JWT), however upon further research we discovered what we're currently developing sessions are a better direction.

A few reasons for the switch are:

  • It is much harder to revoke JWT without significant development investment such as making a blacklist
  • Sessions provide a stronger guarantee that each individual request is authorized and are simpler to implement securely
  • If a user is signed into multiple devices and a condition on the account where to change such as permissions or login status there is no guarantee that all devices will change

Both authentication methods require some consideration in order to prevent their specific vulnerabilities, but at the moment since we have made the decision to go with sessions, we are going to have to spend the time implementing solutions in order to mitigate those vulnerabilities.

Implementing Sessions

Sessions are normally stored in-memory on the server, however you can store sessions elsewhere. If you have a caching service, such as Redis, you might want to use that instead of in-memory storage on the server. Since we are using MySQL or more specifically Sequelize for MySQL, we will store sessions through Sequelize into our MySQL Database.

Install the following packages in order to create & store sessions:

  • express-session
  • connect-session-sequelize

Express-session is used to create sessions with express & connect-session-sequelize to connect express-session to mysql through sequelize.

npm i express-session connect-session-sequelize

NPM Install Command to create sessions & store them in database

In app.js add the following code to use the packages.

const session = require("express-session");
const SequelizeStore = require("connect-session-sequelize")(session.Store);

Use express-session & connect-session-sequlize

Now that we are able to use the packages that we installed. Next we will make sure that the express server is using sessions. For the session configuration we will be defining the following attributes:

  • secret: used to sign the session ID cookie
  • store: where we will be storing the session
  • resave: whether or not we want to force saving sessions to store
  • saveUnitialized: whether or not we want to force saving sessions to store that is uninitiated
  • cookie:
    • maxAge: how long a cookie will live
    • secure: whether or not your site's cookies will be secure, requires HTTPS
    • sameSite: set the Same-Site attribute in cookies
app.use(
	session({
		secret: "{YOUR SECRECT KEY}",
		store: new SequelizeStore({
			db: db.sequelize,
		}),
		resave: false,
		saveUninitialized: false,
		cookie: {
			maxAge: 60000 * 60, 
			secure: false, 
			sameSite: "Lax"
		},
	})
);

app.use for express server to create & store sessions

Now that our server can use sessions, we need to actually create them during our authentication. When registering or logging in with merchants we will create a session and have to be associated with our merchant's id.

req.session.userId = merchant.id;

Make a session and associate it to our merchant id

Adding an Auth Check Middleware

The server can now create & store sessions with that we want to protect our storefront & product routes, by using an authentication check. We created a middleware on our express server that will be in front of certain routes that first checks that they have a session with the server then allows them to perform the actions.

First make a directory in the "src" folder. Next we made a authCheck.middleware.js file that stores our logic for the middleware to be used by our routes. In the authCheck middleware we want to check for 2 things at the moment, one being if they have a session with us and two if that session is in our database. Last we need to make sure that we are exporting it so routes will be able to use them.

module.exports = (req, res, next) => {
	console.log("authCheck middleware triggered");
	
	if (!req.session) {
		return res.status(500).json({ error: "Internal server error" });
	}

	try {
		if (req.session.userId) {
			next();
		} else {
			res.status(401).json({ error: "Unauthorized. Please login." });
		}
	} catch (error) {
		res.status(500).json({ error: "Internal server error" });
	}
};

Middleware to check if merchant has a session & is in the session database

With a middleware created we want to import it in our storefront & product router files.

const authCheck = require("../middleware/authCheck.middleware");

Import authCheck middleware

In the create, update, & delete for both product & storefront we will update the route to have a middleware check. Here is an example of what it should look like:

router.post("/create", authCheck, createProduct);

Example for authCheck

When a route is triggered it does the following, first it does the authCheck middleware, if successful it moves onto the controller code and if nothing goes wrong it will complete the code and respond to the merchant.

Updating Merchants & Products

There are some slight tweaks we want to get handled now while we are updating the security for the server. We want to update the merchant to collect first & last names & update products to have storefront association.

In the merchant model we updated the model to include first name & last name with the data type being STRING & allowNull to be false. This means that in the MySQL Table that we will store the data as strings and it cannot be null value.

Similar to the merchant model we updated the product model to include storefront id with a STRING data type & allowNull to be false. This means that every product will be associated with a storefront.

In the merchant controller, we collect the first name & last name when registering a merchant. At this time we don't have anything developed to update a merchants information or even the password. For the product we collect the storefront id when creating a product. When updating a product we shouldn't be able to switch products to a different storefront so we don't collect it during that.

Future Plans

Our next part we want to develop "customers" and the necessary features for that, which will include:

  • Completing transactions
  • Having an order history
  • User authentication.
  • User Profiles

For the security we want to handle data sanitization to lower our risk of SQL Injections, rate limiting to prevent abuse & DoS attacks. There are additional benefits to rate limiting besides those two such as resource management.

Once we implement "customers" we want to update the Personal Identifiable Information (PII) to have psuedonymization when storing data in the database.

If you would like to check out the code or us it for yourself: Github Link