Implementing Blind Indexes in Laravel

What is a blind index?

Blind indexing is an approach to securely search encrypted data with minimal information leakage.

Use case

Let’s say that you are building a platform which is going to store large amounts of personal information. Data such as SSN numbers, Aadhaar card or Pan card etc. You also need the ability to search through them to run validation checks etc.

Implementation

First you need to have your application and database servers running on different machines. You obvious don’t want your SALT keys and database to be on the same machine.

Let’s assume your table schema looks something like this (PostgreSQL):

    id SERIAL PRIMARY KEY,
first_name TEXT,
last_name TEXT,
ssn TEXT, /* encrypted */
ssn_bidx TEXT /* blind index */
);CREATE INDEX ON users(ssn_bidx);

The ssn column stores the encrypted value and ssn_bidx column stores the blind index value.

Laravel Implementation

The below implementation leverages Laravel’s accessors and mutators to access attributes before saving and after retrieving data from database.

The following set of files will enable Laravel’s QueryBuilder to read an array of encrypted column names in a model. This is basically a mapping between your encrypted column name and blind index column name. That way you can simply add$encrypted property to your models and the implementation will automatically encrypt all new data thats being saved and retrieved.

Let’s start with creating a Blind index trait inside the App\Model\Concerns folder. Below is an example of what a Blind Index trait would look like.

Let’s create another trait for SSN (whatever encrypted field name is), so this can be utilized by multiple models across the application.

        return '';
}
}

You also need to overwrite Laravel’s QueryBuilder, so it runs your where conditions on ssn_bidx instead of ssn field. Below is the implementation of extending Laravel’s QueryBuilder with a custom query builder.

Your custom QueryBuilder trait.

namespace App\Models\Concerns;

use App\Models\Eloquent\Builder;

trait QueryBuilder
{

/**
*
@param $query
*
@return Builder
*/
public function newEloquentBuilder($query)
{
return new Builder($query);
}
}

And now the BlindIndexEncryption file.

Finally, now in your model class you can add the above traits we created.

namespace App\Models;use App\Models\Concerns;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
use
Concerns\QueryBuilder,
Concerns\SocialSecurityNumber,
Concerns\BlindIndex;
protected $table = 'users';
protected $guarded = ['id', 'created_at', 'updated_at'];
/**
*
@var string[]
* Blind Indexes columns in DB
*/
protected $encrypted = [
'ssn' => 'ssn_bidx',
];
}

Writing queries

Or$user = User::where('ssn', $request->ssn)->exists();

That’s it!

Your encrypted data is now searchable!

Notes:

  • The above code was tested with Laravel 5.8 ≤8
  • Works with MySQL, PostgreSQL and MongoDB databases.
  • Should work fine with any database as Eloquent handles it very nicely.
  • Works with PHP 7.x +only
  • Test your code well after implementation.
  • The above implementation does not support Fuzzy search. You can only run a full match query.

Written by

Product Lead at StegoSOC

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store