DEV Community

Cover image for fastify-hashids: Obscure Your Database IDs Like a Pro!
Anderson. J
Anderson. J

Posted on

fastify-hashids: Obscure Your Database IDs Like a Pro!

Greetings, fellow developers! Today, I'd like to introduce you to a Fastify plugin that can significantly simplify handling sensitive data in your applications. Say hello to Fastify Hashids! This plugin seamlessly integrates Hashids into your routes, providing a straightforward way to encode and decode data securely.

The Why behind Fastify Hashids

When building web applications, it's common to use numerical IDs as primary keys in databases. However, these IDs can unintentionally leak sensitive information due to their sequential nature. For instance, if records receive IDs in ascending order, it's easy to infer the total number of records present. This seemingly harmless detail might indirectly reveal additional information like the total number of users, orders, or partial revenue, potentially posing a security risk.

Hashids comes to the rescue by obfuscating numbers, effectively resolving this issue. Here's an example of how it works:

ID Encoded ID
1 olejRejN
2 pmbk5ezJ
3 pnel5aKB
4 MvbmOeYA
5 openRe7A

You can find more details about hashids in the official documentation.

Now, my approach when working with Fastify involves using sequential numeric IDs on the backend. However, the real magic happens when data flows in and out of the server. At that point, I implement a hashing layer using Fastify Hashids to ensure robust security without complicating things internally.

Hashing a response with fastify-hashids

Using Fastify Hashids

To get started, let's install the necessary packages for your project. Open your terminal and run:

pnpm install fastify fastify-hashids
Enter fullscreen mode Exit fullscreen mode

With the packages installed, let's put Fastify Hashids to work by creating a basic Fastify server.

// index.mjs
import Fastify from 'fastify'
import { randomInt } from 'crypto'

const fastify = Fastify({
  logger: true
})

// Declare a route
fastify.get('/user', async function handler (request) {
  const id = randomInt(100000);
  const name = 'John'

  request.log.info({originalId: id});
  return { 
    id,
    name
  }
})

// Run the server!
try {
  await fastify.listen({ port: 3000 })
} catch (err) {
  fastify.log.error(err)
  process.exit(1)
}
Enter fullscreen mode Exit fullscreen mode

If we start our server using node index.mjs and make some requests to it, we'll see the following output:

curl localhost:3000
{"id": 85171, "name": "John"}
Enter fullscreen mode Exit fullscreen mode

Additionally, the console will display logs like this:

{"level":30,"time":1690406026744,"pid":59530,"hostname":"ander-server","reqId":"req-2","originalId": 85171}
{"level":30,"time":1690406026744,"pid":59530,"hostname":"ander-server","reqId":"req-2","res":{"statusCode":200},"responseTime":0.5319289565086365,"msg":"request completed"}
Enter fullscreen mode Exit fullscreen mode

Notice the "originalId": 85171 in the logs, helping us track the original ID before encoding.

Now, let's integrate Fastify Hashids. All we need to do is import it and register it. That's it!

// Import the framework and instantiate it
import Fastify from 'fastify'
import fastifyHashids from 'fastify-hashids'
import {randomInt} from 'crypto'

const fastify = Fastify({
  logger: true
})

// Register Fastify Hashids
await fastify.register(fastifyHashids);

// Declare a route
fastify.get('/user', async function handler (request) {
  const id = randomInt(100000);
  const name = 'John'

  request.log.info({originalId: id});
  return { 
    id,
    name
  }
})

// Run the server!
try {
  await fastify.listen({ port: 3000 })
} catch (err) {
  fastify.log.error(err)
  process.exit(1)
}

Enter fullscreen mode Exit fullscreen mode

With this integration, the output will look different:

curl localhost:3000
{"id": "jy2z", "name": "John"}
Enter fullscreen mode Exit fullscreen mode

The console will still display the original ID without encoding:

{"level":30,"time":1690406026744,"pid":59530,"hostname":"ander-server","reqId":"req-2","originalId": 79501}
Enter fullscreen mode Exit fullscreen mode

Pretty cool, right?

Fastify Hashids also offers some options for fine-tuning your hashing experience. You can pass the following options to the plugin:

  • hashidsOptions.idRegexp: A regular expression that fastify-hashids uses to automatically identify properties as IDs. By default, it matches variations of "id, ids, ID, userID," etc. You can customize this regex to match your specific property names. Set it to null to disable the regex-based identification.

  • hashidsOptions.propertyList: An array of property names to include in the hashing process. Properties listed here will be considered for encoding with Hashids, in addition to those identified by the idRegexp.

For more options, such as salt and minimum length, check out the hashids.js repo.

Wrap-Up

Fastify Hashids is a great tool that effortlessly integrates Hashids into your Fastify applications. It's perfect for securing sensitive data like database IDs, enhancing your application's security without adding unnecessary complexity.

Since this plugin is open-source, you're welcome to contribute, report issues, or suggest improvements.

Happy coding! 🚀

Oldest comments (0)