Healthcare SaaS HIPAA Compliance: Technical Rules

The fastest way to fail a healthcare security review is to confuse "we encrypt the database" with HIPAA compliance. Whole-disk encryption protects you from a thief carrying off a hard drive; it does nothing against the SQL injection or stolen credential that queries your database and gets plaintext back. Real compliance is a stack of specific technical controls — and with the average breach now costing $4.88M (IBM, 2024) and healthcare among the most expensive verticals, the gap between "we have a privacy policy" and "we'd survive an audit" is where the seven-figure risk lives.
Here's what actually passes: field-level encryption for PHI, TLS 1.3 in transit, immutable audit logs, least-privilege access with MFA, a signed BAA with every vendor, and automated breach detection. None of it is optional, and a privacy policy is none of it. Here are the seven technical rules.

Rule 1: Know What PHI Actually Is
HHS defines Protected Health Information through 18 identifiers, and developers consistently underestimate the scope. It's not just charts and prescriptions — a name, email, zip code, IP address, or birth date linked to any health context makes the entire row regulated PHI. If your appointments table joins to an email, that email is now PHI. Map every place an identifier touches health data before you write a line of access control, because you can't protect data you haven't classified.
Rule 2: Field-Level Encryption, Not Just Disk Encryption
Disk encryption is a baseline, not a defense — a compromised query returns decrypted data. Add application-layer field-level encryption (AES-256-GCM) for PHI columns, before the data ever reaches Postgres:
1// src/crypto/field-encryptor.service.ts
2import { Injectable } from '@nestjs/common';
3import * as crypto from 'crypto';
4
5@Injectable()
6export class FieldEncryptorService {
7 private readonly algorithm = 'aes-256-gcm';
8 private readonly key = Buffer.from(process.env.PHI_ENCRYPTION_KEY_HEX!, 'hex');
9
10 encrypt(plain: string): { data: string; iv: string; tag: string } {
11 const iv = crypto.randomBytes(12);
12 const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);
13 const data = cipher.update(plain, 'utf8', 'hex') + cipher.final('hex');
14 return { data, iv: iv.toString('hex'), tag: cipher.getAuthTag().toString('hex') };
15 }
16}Keep the key in a KMS or HSM, never beside the data — ideally with envelope encryption (a per-record data key wrapped by a master key) so one leaked key doesn't expose everything. Now a stolen database dump is ciphertext. This is the same "never roll your own crypto, use the vetted primitive" discipline, applied at the column.

Rule 3: Enforce TLS 1.3 in Transit
Every request, webhook, and internal hop must be encrypted. Configure your load balancer to require TLS 1.3 (drop TLS 1.0/1.1), send HSTS headers so browsers refuse plain HTTP, and keep backend service-to-service traffic inside a VPC or service mesh. There's no "internal network so it's fine" in healthcare — encrypt it all.
Rule 4: Make Audit Logs Immutable
HIPAA requires logging every access to PHI — read, write, export, delete — and the log must be tamper-proof, unchangeable even by a root DBA. Block mutations at the database and ship to WORM storage:
1CREATE TABLE hipaa_audit_ledger (
2 id BIGSERIAL PRIMARY KEY,
3 tenant_id UUID NOT NULL,
4 acting_user_id UUID NOT NULL,
5 patient_id UUID NOT NULL,
6 action VARCHAR(20) NOT NULL CHECK (action IN ('CREATE','READ','UPDATE','DELETE','EXPORT')),
7 client_ip VARCHAR(45) NOT NULL,
8 user_agent TEXT,
9 occurred_at TIMESTAMPTZ DEFAULT NOW()
10);
11
12-- Reject any attempt to change or delete an audit row.
13CREATE RULE no_audit_update AS ON UPDATE TO hipaa_audit_ledger DO INSTEAD NOTHING;
14CREATE RULE no_audit_delete AS ON DELETE TO hipaa_audit_ledger DO INSTEAD NOTHING;Mirror it to append-only storage like S3 Object Lock. Auditors don't ask whether you log access — they ask you to produce who read a specific patient's record and when, which is exactly what a real enterprise audit log is for.
Rule 5: Least Privilege, MFA, and Short Sessions
The "minimum necessary" standard is law, not a nice-to-have:
- RBAC — a billing clerk sees invoice lines, never clinical notes. Scope every role to the minimum, enforced with a real role-based permission system.
- MFA everywhere — stolen credentials start about 24% of breaches (Verizon DBIR 2024); a second factor is the cheapest control that moves the needle.
- Auto-logout — terminate sessions after ~15 minutes idle so an unattended workstation isn't an open chart.

Rule 6: Sign a BAA With Every Vendor
You cannot run healthcare SaaS on consumer hosting. Every vendor that touches PHI — cloud, email, monitoring — must sign a Business Associate Agreement binding them to HIPAA. No BAA, no PHI on that service, full stop. Build only on HIPAA-eligible offerings under a signed BAA:
A flawless encryption setup on a host that won't sign a BAA is still a violation — the legal accountability is part of the control.
Rule 7: Detect Breaches Automatically
HIPAA mandates breach notification within 60 days of discovery, which means you have to discover it. Stream security telemetry to a tool like GuardDuty or Datadog and set automated triggers for anomalies — an account reading 500 patient records in ten seconds, access from an impossible location — that freeze the session token immediately to stop exfiltration. And scrub PHI out of your logs at the source: an unhandled error that prints a patient field into stdout can leak straight into Sentry, so filter sensitive patterns before they leave your servers.
The HIPAA Compliance Technical Checklist
| Layer | Insufficient | Audit-ready |
|---|---|---|
| At rest | Disk encryption only | Field-level AES-256 + KMS |
| In transit | Mixed HTTP/HTTPS | TLS 1.3 + HSTS |
| Audit | Mutable log files | Immutable WORM ledger |
| Access | Shared roles | Least privilege + MFA |
| Vendors | Consumer hosting | Signed BAAs only |
HIPAA compliance isn't a badge you buy or a clause you paste into a footer — it's encryption at the column, a log you can't alter, access scoped to the minimum, and a contract with everyone who touches the data. Build those controls in from the first commit, because retrofitting them after you've stored real PHI is how a "we'll handle compliance later" becomes a breach notification with your name on it. Get the boring controls right, and the audit becomes paperwork instead of a panic.
Frequently Asked Questions
More than you think. HHS defines Protected Health Information through 18 identifiers, and any of them linked to health data makes the whole record regulated — name, email, zip code, IP address, birth date, device IDs, and more. If your database connects a patient's email to an appointment, that row is PHI and must be encrypted, access-controlled, and audited. Treat anything that can identify a person alongside health context as regulated.
No. Disk encryption protects against a stolen physical drive, but it does nothing if an attacker reaches your database through SQL injection or stolen credentials — the data decrypts transparently for any query. To pass a serious audit, add application-layer field-level encryption (AES-256-GCM) for PHI columns, with keys held in a KMS or HSM separate from the database. Then a leaked database dump is ciphertext, not patient records.
Yes, with every vendor that touches PHI — your cloud host, email provider, monitoring tool, everything. A BAA legally binds them to protect the data under HIPAA. Running patient data on a host that won't sign one is a direct violation regardless of how well you've encrypted things. Build only on HIPAA-eligible services from AWS, Google Cloud, or Azure, each under a signed BAA.
Immutably. Every read, write, export, and delete of PHI must be logged, and the log must be tamper-proof — unchangeable even by a database admin. Block UPDATE/DELETE on the audit table and ship a copy to append-only WORM storage like S3 Object Lock. Auditors don't ask whether you log access; they ask you to produce who accessed a specific record and when, and the answer has to be trustworthy.
Not the actual health information. Standard SMS is unencrypted, so never put diagnoses, results, or treatment details in a text. Keep messages generic — 'a new update is available in your secure portal' — and require the patient to authenticate in the app to read anything sensitive. The same goes for email and push: the notification can say something's ready; it can't be the something.
