← Recipes

阅读中文版本

Hash PII with a Bloom Filter for Set Membership

Hash personally identifiable information into a Bloom filter so you can test membership without storing the raw values, and size the filter for your false-positive budget.

~25 minprivacybloom-filterpii

Task

Build a Bloom filter that lets the support team check whether an email belongs to a known customer without exposing the email list.

When to use this

Support wants to know if a caller is already a customer, but the customer email list is sensitive and cannot be shared with the support tooling. The team needs a membership test that does not reveal the underlying emails.

Prerequisites

  • A list of PII values to load into the filter
  • A Bloom filter library with a known false-positive rate parameter
  • A runtime that can serve the serialized filter to the support tool

Steps

1. Size the filter for the expected element count and a one-percent false-positive rate.

import { BloomFilter } from "bloom-filters";
const filter = BloomFilter.create(1_000_000, 0.01);

Expected output: A BloomFilter sized for one million elements with a false-positive rate of 0.01, using about 1.2 MB of memory.

2. Hash each PII value into the filter and serialize the result for distribution.

for (const email of customerEmails) filter.add(email);
const blob = filter.saveAsJSON();

Expected output: A serialized blob that can be loaded by any process without access to the original email list.

3. Test membership at query time and treat a positive as a probable match, not a certainty.

node -e "const f = BloomFilter.fromJSON(blob); console.log(f.has(query));"

Expected output: A boolean where false is certain and true is correct 99 percent of the time, with the remaining one percent handled by a follow-up authoritative check.

Troubleshooting

Problem

False positives erode trust in the membership answer

Solution

Lower the false-positive rate to 0.001 at the cost of a larger filter, or confirm positives with an authoritative lookup before acting.

Problem

The filter cannot be updated incrementally

Solution

Rebuild and redistribute the filter on a schedule; a counting Bloom filter supports deletion but at a significant memory cost.

Limitations

  • A Bloom filter cannot remove elements; a deletion requires a rebuild.
  • The false-positive rate is probabilistic, so any positive answer must be treated as a hint, not a proof.

Membership without exposure

A Bloom filter answers “is this email a customer?” without storing the emails. Load the PII once, serialize the filter, and distribute the blob. The support tool loads the blob and never sees the raw values.

import { BloomFilter } from 'bloom-filters';
const filter = BloomFilter.create(1_000_000, 0.01);
for (const email of customerEmails) filter.add(email);
const blob = filter.saveAsJSON();

Size for your error budget

The false-positive rate trades memory for accuracy. At one percent, one million elements need about 1.2 MB. At 0.1 percent, the same count needs about 1.8 MB. Pick the rate that your follow-up process can tolerate, and confirm positives with an authoritative check before acting on them.

Expected outcome

The support tool answers membership in microseconds, never receives the email list, and a false answer is always correct. A true answer is correct 99 percent of the time, with the remaining one percent caught by the authoritative follow-up.