Get a Pentest and security assessment of your IT network.

Cyber Security

Using BCrypt Hashes as Database IDs

TL;DR

Storing BCrypt hashes directly in your database as primary keys can improve security by making ID guessing harder. However, it introduces complexities with indexing and retrieval. This guide explains how to do it safely and effectively.

1. Why Use a BCrypt Hash for IDs?

Traditional auto-incrementing integer IDs are predictable. An attacker knowing the range of your IDs can potentially guess valid records. Using a BCrypt hash (which is designed to be one-way) makes ID guessing significantly more difficult.

2. Generating the Hash

  1. Choose a Salt: A salt is random data added to the password before hashing. You’ll need to store this salt alongside the hash.
  2. Hash the Data: Use a strong BCrypt library in your chosen programming language. The input should be unique data associated with each record (e.g., timestamp, username, email). Do not use passwords!

Example using Python and the bcrypt library:

import bcrypt

data = "unique_record_identifier"
# Generate a salt
salt = bcrypt.gensalt()

# Hash the data with the salt
hash = bcrypt.hashpw(data.encode('utf-8'), salt)

print(f"Hash: {hash.decode('utf-8')}")

Store both the hash and salt in your database table.

3. Database Table Structure

Your database table should include at least these columns:

  • id: VARCHAR(255) – Stores the BCrypt hash (primary key).
  • salt: VARCHAR(255) – Stores the salt used for hashing.
  • Other relevant data columns

The id column should be set as your primary key.

4. Retrieving Data

  1. Hash the Input: When searching for a record, hash the same unique identifier you used to generate the original ID using the stored salt.
  2. Compare Hashes: Compare the generated hash with the hash stored in the database. If they match, you’ve found the record.

Example (Python):

import bcrypt

data_to_search = "unique_record_identifier"
hash_from_db = "your_stored_hash"
salt_from_db = "your_stored_salt".encode('utf-8')

# Hash the input data using the stored salt
hashed_data = bcrypt.hashpw(data_to_search.encode('utf-8'), salt_from_db)

# Compare the generated hash with the database hash
if hashed_data == hash_from_db:
    print("Record found!")
else:
    print("Record not found.")

5. Indexing Considerations

BCrypt hashes are long strings, making traditional indexing less effective. Consider these options:

  • Full-Text Search: If your database supports it, use full-text search on the id column.
  • Prefix Indexing: Index only a portion of the hash string (e.g., the first 10 characters). This reduces index size but increases the risk of collisions.
  • Avoid Indexing: For smaller datasets, you might be able to avoid indexing altogether and rely on full table scans.

Test performance carefully with realistic data volumes.

6. Security Best Practices

  • Never Store Passwords Directly: BCrypt is for password hashing, not ID generation. Use it only with unique record identifiers.
  • Use a Strong Library: Choose a well-maintained and reputable BCrypt library.
  • Salt Uniqueness: Ensure each record has a unique salt.
  • Regularly Review: Re-evaluate your security measures as technology evolves.
Related posts
Cyber Security

Zip Codes & PII: Are They Personal Data?

Cyber Security

Zero-Day Vulnerabilities: User Defence Guide

Cyber Security

Zero Knowledge Voting with Trusted Server

Cyber Security

ZeroNet: 51% Attack Risks & Mitigation