How I am implementing an encryption middleware for ids?

In this post, I elaborate the process of choosing the most effective solution for encrypting and decrypting database ids when sending over a network for security purposes.

How I am implementing an encryption middleware for ids?

One of the security features to implement is to encrypt any database model ids when sending and receiving data, for example, in an object with a list of products, the product_id changes from 1 to 92f06e135b1749215c2a2bbc6261ffaa.

Strategies

In my experience, we can do that in three ways:

  1. Function
  2. Decorator
  3. Middleware

The main idea is straightforward: to encrypt the ids on sending the response to the client and decrypt when receiving them back.

Function

The first way to abstract the logic and make it easier to manage changes, such as changing libraries, is to write a utility class or object with two functions encrypt and decrypt. You can also add a third one, namely process, which will apply the transformation. You can either match the property name exactly, or have a match on any one with _id; or have an array name storing the properties you want to encrypt or decrypt.

PROS

This method is simple to add and quick to make it work for a small project with little amount of APIS.

CONS

A lot of work is required as you need to make the same changes at every endpoint that is going to send or receive data. You need to code each one individually. You will also need to change existing API functions which can break existing and important features. This is contrary to the Open/Closed Principle in SOLID, which states that behaviours can be extended without having to modify the source code.

Decorator

A more effective solution is the use of decorator, which also applies the Open/Closed Principle. You don't need to change the existing functions but only apply the decorator (therefore extending the behaviour).

This concept might be a bit difficult for novice programmers, but it's certainly an interesting solution especially for complex systems with plenty of dependencies and the risk of regressions.

At the present stage, there is no plain and simple decorator available in JavaScript, but exists in TypeScript. Additionally, there are different types of decorator, namely, method, class, accessor and parameter.

For this scenario, you can either use class or method decorator. With method, you need to apply it in each of your functions, which is cumbersome. With the class one, you apply it only once before your class definition; however, the logic might be a bit more tricky as you now need to also loop through each methods. Furthermore, if you can only use class decorator if you are using classes and not objects.

The logic is that you have a nested loop through each method and its respective parameters to determine if the id exists, and if so encrypt or decrypt.

https://codeburst.io/decorate-your-code-with-typescript-decorators-5be4a4ffecb4

CONS

Understanding decorators is not a trivial matter, let alone implementing it. Moreover, if you still have many API classes, you need to do the change in several places.

This solution is nevertheless classier than using functions or method/parameter decorator.

You may be thinking: is there another easier solution? Decorators might be not everyone's cup of tea.

There is indeed a much simple and interesting solution.

Middleware

For this solution, I started with the function based approach but doing this requires too much work. As I am using CoffeeScript, creating and using decorators seem foreign and not as easy to create as TypeScript.

There are different types of middleware in Express namely application, router, error, built-in and third party. For our scenario, an application middleware is suitable.

ExpressJS

PRO

The biggest advantage using a middleware is that you make the change at a single point. You basically intercept the incoming request or outgoing response and modify your ids respectively.

In addition, you can also pack your middleware into a module and reuse for other projects using underlying similar technologies, in this case, Express.

The process

I am using NodeJS own crypto module for the encryption and decryption. I begin writing these functions and their tests with Mocha/Chai/Sinon in the application itself before then moving the logic in the services file where express is found. (From function to middleware)

For the middleware itself, I code it in this way app.use fn -> req, res, next. I, however, struggle to manipulate the data asynchronously. I write a function called transform for looping through the keys if the response is both an object or an array of objects. I try processing the whole thing as Promises in order to avoid the async issue or nature of NodeJS.

Even by separating the constructing/deconstructing into Promise and sending the data with Promise.all, the middleware still sends the response before all objects can be manipulated. I try several other interceptor libraries such as express-hijackresponse and tamper, but to no avail. They either don't work or still send the data asynchronously.

Finally, as I usually do when stuck with a obstinate problem, I return to the basics. I glance at a couple of beginner tutorial on using middleware for express, where I discover Express-Mung, a simple library that abstracts manipulating the body object.

I nevertheless can't make it work because still of the async problem. I also try working with the Async library that I previously used for building data for pivot tables; but still same issue.

I proceed to go back a step and read each APIs. I have the habit to often jump right into the first solution that pops in front of me instead of diligently working out the APIs.

This approach is effective for quick solutions such as fs.readAsync but in this case, even if express-mung does not have a lot of APIs, noticing one of them makes all the difference.

By using mung.jsonAsync, the body returned the correct set of data.

Async