Skip to content

MuhdHanish/queryable_encryption_mongodb_node

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Queryable Encryption with MongoDB in Node.js

This project demonstrates how to implement Client-Side Field Level Encryption (CSFLE) using MongoDB and Node.js. It uses Queryable Encryption to allow searching on encrypted fields, such as emails, while keeping the data secure. Sensitive fields like passwords and Social Security Numbers (SSNs) are encrypted using MongoDB's CSFLE feature.

Table of Contents

Features

  • Queryable Encryption: Perform equality queries on encrypted fields (e.g., search users by email).
  • Field-Level Encryption: Encrypt sensitive fields such as passwords and SSNs using random encryption.
  • Local Key Management: Supports local KMS (Key Management System) with a base64-encoded master key.
  • Secure Registration and Query: Registers new users with encrypted fields and allows searching users by email.

Prerequisites

Before you can run this project, ensure you have the following:

  1. MongoDB 4.2+: You need MongoDB 4.2 or later with support for Client-Side Field Level Encryption (CSFLE).
  2. Node.js: Ensure you have Node.js installed (version 14+ is recommended).
  3. MongoDB URI: You need access to a MongoDB instance (either locally or via MongoDB Atlas).
  4. Master Key: A base64-encoded master key for local KMS (for demo purposes).

Installation

  1. Clone this repository:

    git clone https://github.com/MuhdHanish/queryable_encryption_mongodb_node.git
  2. Navigate into the project directory:

    cd queryable_encryption_mongodb_node
  3. Install the required dependencies:

    npm install

Environment Variables

You need to create a .env file in the root of the project with the following variables:

MONGO_URI=mongodb+srv://<username>:<password>@cluster0.mongodb.net/mydb?retryWrites=true&w=majority
MASTER_KEY=your_base64_encoded_master_key
PORT=8000  # Port number for the server

How to Generate a Master Key (with OpenSSL)

For the local KMS provider, you need a 96-byte key. You can generate it using the openssl command:

openssl rand -base64 96

This will output a base64-encoded 96-byte key, which you can store in your .env file as MASTER_KEY.

How to Generate the Key ID

In the code, a Key ID (used for encrypting data fields) will be generated automatically if it doesn't exist. When running the server for the first time, it will generate the Key ID and prompt you to add it to the .env file.

To create the KEY_ID:

  1. Run the following command:

    npm run start:dev
  2. If the KEY_ID is not set in your .env, the application will generate a new key and print it in the console:

    Add this KEY_ID to your .env file: <generated_key_id>
  3. Copy the generated key and add it to the .env file as follows:

    KEY_ID=your_base64_encoded_key_id

This KEY_ID is necessary for encrypting the data fields and will be used in future operations.

How It Works

  • Deterministic Encryption: Allows for queries on fields like email.
  • Random Encryption: Provides stronger security for fields like password and ssn, but does not support querying.
  • The app uses MongoDB's native client (mongodb package) to perform encryption. Mongoose is also used for schema management, but MongoClient is required for handling encrypted fields.

Running the App

Once you've configured everything, you can start the app:

npm run start:dev

The app will run on the port defined in your .env file (default: 8000).

API Endpoints

Register a New User

  • URL: /api/register
  • Method: POST
  • Description: Registers a new user and encrypts sensitive fields such as email, password, and ssn.

Request Body:

{
  "name": "John Doe",
  "email": "john@example.com",
  "password": "supersecret",
  "ssn": "123-45-6789"
}

Response:

{
  "message": "User registered successfully",
  "userId": "<MongoDB Document ID>"
}

Retrieve User by Email

  • URL: /api/user/:email
  • Method: GET
  • Description: Retrieves a user by their email. Only non-sensitive fields are returned (i.e., password and SSN are excluded).

Response:

{
  "name": "John Doe",
  "email": "john@example.com"
}

Schema Map

The encryption schema used by MongoDB to encrypt specific fields:

const schemaMap = {
  "queryable_encryption.users": {
    bsonType: "object",
    encryptMetadata: {
      keyId: [new Binary(Buffer.from(process.env.KEY_ID!, 'base64'), 4)]
    },
    properties: {
      email: {
        encrypt: {
          bsonType: "string",
          algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
        }
      },
      password: {
        encrypt: {
          bsonType: "string",
          algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
        }
      },
      ssn: {
        encrypt: {
          bsonType: "string",
          algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
        }
      }
    }
  }
};

Encryption Algorithms

  • Deterministic Encryption: Used for the email field, allows queries on encrypted data.
  • Random Encryption: Used for sensitive fields like password and ssn, provides stronger security but no querying capabilities.

Feedback

If you have any feedback, please reach me at muhammedhanish11@gmail.com or connect with me on LinkedIn.

Support

Show your support by 🌟 starring the project!!