-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Priority
P0
Story Points
13
Dependencies
Depends on #5 (Authentication), #6 (Shared Libraries), #8 (Monitoring)
Summary
Implement comprehensive HIPAA security controls including audit logging for PHI access, encryption at rest/transit, data retention policies, consent management, and security incident response procedures to ensure full compliance with healthcare regulations.
Background
HIPAA (Health Insurance Portability and Accountability Act) requires specific security measures for protecting Protected Health Information (PHI). Current gaps:
- No audit logging for PHI access
- No encryption at rest enforcement
- No data retention/deletion policies
- No consent management system
- No security incident response procedures
- No PHI de-identification utilities
Acceptance Criteria
Administrative Safeguards:
- Security incident response plan and procedures
- Security awareness training materials
- Access management policies (role-based access control)
- Workforce security policies documented
Physical Safeguards:
- Workstation security guidelines
- Device and media controls documented
Technical Safeguards:
- Audit logging for ALL PHI access (read, write, modify, delete)
- Encryption at rest for database and file storage
- Encryption in transit (TLS 1.3 minimum)
- Access control implementation with unique user IDs
- Automatic logoff after inactivity period
- Emergency access procedures
Additional Requirements:
- Data retention policies (minimum 6 years for HIPAA)
- Secure data deletion procedures
- PHI de-identification utilities
- Patient consent management system
- Breach notification procedures
- Business Associate Agreement (BAA) templates
Technical Implementation
Audit Logging for PHI Access
Enhanced Audit Log Schema:
CREATE TABLE phi_access_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id),
patient_id UUID REFERENCES patients(id),
encounter_id UUID REFERENCES encounters(id),
action VARCHAR(50) NOT NULL, -- 'read', 'write', 'update', 'delete'
resource_type VARCHAR(100) NOT NULL,
resource_id UUID,
phi_fields TEXT[], -- Array of PHI fields accessed
ip_address INET,
user_agent TEXT,
session_id UUID,
timestamp TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
justification TEXT, -- Required for break-glass access
-- Indexes for common queries
CONSTRAINT valid_action CHECK (action IN ('read', 'write', 'update', 'delete'))
);
CREATE INDEX idx_phi_access_user_date ON phi_access_logs(user_id, timestamp DESC);
CREATE INDEX idx_phi_access_patient ON phi_access_logs(patient_id, timestamp DESC);
CREATE INDEX idx_phi_access_timestamp ON phi_access_logs(timestamp DESC);Audit Logging Middleware:
import { Request, Response, NextFunction } from 'express';
import { getDatabase } from '@scribemed/database';
import { logger } from '@scribemed/logging';
export interface PHIAccessContext {
patientId?: string;
encounterId?: string;
resourceType: string;
resourceId?: string;
action: 'read' | 'write' | 'update' | 'delete';
phiFields?: string[];
}
export async function logPHIAccess(
userId: string,
context: PHIAccessContext,
req: Request
): Promise<void> {
const db = await getDatabase();
try {
await db.query(
`INSERT INTO phi_access_logs (
user_id, patient_id, encounter_id, action, resource_type,
resource_id, phi_fields, ip_address, user_agent, session_id
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,
[
userId,
context.patientId || null,
context.encounterId || null,
context.action,
context.resourceType,
context.resourceId || null,
context.phiFields || [],
req.ip,
req.get('user-agent'),
req.user?.sessionId || null,
]
);
logger.info('PHI access logged', {
userId,
action: context.action,
resourceType: context.resourceType,
patientId: context.patientId,
});
} catch (error) {
logger.error('Failed to log PHI access', { error, userId, context });
// Don't throw - logging failure shouldn't break the request
}
}Encryption at Rest
PostgreSQL Transparent Data Encryption:
-- Enable pgcrypto extension
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Encrypt sensitive columns
CREATE TABLE patients (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
ssn_encrypted BYTEA, -- Encrypted SSN
medical_record_number_encrypted BYTEA,
-- ... other fields
);
-- Encryption/decryption functions
CREATE OR REPLACE FUNCTION encrypt_field(plaintext TEXT, key TEXT)
RETURNS BYTEA AS $$
BEGIN
RETURN pgp_sym_encrypt(plaintext, key);
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION decrypt_field(ciphertext BYTEA, key TEXT)
RETURNS TEXT AS $$
BEGIN
RETURN pgp_sym_decrypt(ciphertext, key);
END;
$$ LANGUAGE plpgsql;Application-Level Encryption:
import crypto from 'crypto';
export class PHIEncryption {
private algorithm = 'aes-256-gcm';
private key: Buffer;
constructor() {
const encryptionKey = process.env.PHI_ENCRYPTION_KEY;
if (!encryptionKey) {
throw new Error('PHI_ENCRYPTION_KEY not configured');
}
this.key = Buffer.from(encryptionKey, 'hex');
}
encrypt(plaintext: string): string {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
// Return IV + AuthTag + Encrypted data
return iv.toString('hex') + ':' + authTag.toString('hex') + ':' + encrypted;
}
decrypt(ciphertext: string): string {
const parts = ciphertext.split(':');
const iv = Buffer.from(parts[0], 'hex');
const authTag = Buffer.from(parts[1], 'hex');
const encrypted = parts[2];
const decipher = crypto.createDecipheriv(this.algorithm, this.key, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
}Data Retention & Deletion
Retention Policy Implementation:
// packages/utils/src/data-retention.ts
export interface RetentionPolicy {
resourceType: string;
retentionPeriodYears: number;
archiveBeforeDelete: boolean;
}
const HIPAA_RETENTION_POLICIES: RetentionPolicy[] = [
{ resourceType: 'clinical_notes', retentionPeriodYears: 6, archiveBeforeDelete: true },
{ resourceType: 'encounters', retentionPeriodYears: 6, archiveBeforeDelete: true },
{ resourceType: 'prescriptions', retentionPeriodYears: 7, archiveBeforeDelete: true },
{ resourceType: 'audit_logs', retentionPeriodYears: 6, archiveBeforeDelete: false },
];
export async function applyRetentionPolicy(policy: RetentionPolicy): Promise<void> {
const db = await getDatabase();
const cutoffDate = new Date();
cutoffDate.setFullYear(cutoffDate.getFullYear() - policy.retentionPeriodYears);
// Archive data if required
if (policy.archiveBeforeDelete) {
await archiveOldData(policy.resourceType, cutoffDate);
}
// Soft delete old records
await db.query(
`UPDATE ${policy.resourceType}
SET deleted_at = CURRENT_TIMESTAMP
WHERE created_at < $1 AND deleted_at IS NULL`,
[cutoffDate]
);
}Consent Management
Consent Schema:
CREATE TABLE patient_consents (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
patient_id UUID NOT NULL REFERENCES patients(id),
consent_type VARCHAR(100) NOT NULL,
granted BOOLEAN NOT NULL,
granted_at TIMESTAMP WITH TIME ZONE,
revoked_at TIMESTAMP WITH TIME ZONE,
expires_at TIMESTAMP WITH TIME ZONE,
granted_by_user_id UUID REFERENCES users(id),
purpose TEXT,
scope TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT valid_consent_type CHECK (consent_type IN (
'treatment',
'data_sharing',
'research',
'marketing',
'third_party_access'
))
);Implementation Steps
-
Phase 1: Audit Logging (Week 1-2)
- Create PHI access log schema
- Implement audit logging middleware
- Add to all PHI-accessing endpoints
-
Phase 2: Encryption (Week 2-3)
- Configure encryption at rest
- Implement application-level encryption
- Enforce TLS 1.3
-
Phase 3: Data Retention (Week 3)
- Implement retention policies
- Create archival procedures
- Add secure deletion
-
Phase 4: Consent Management (Week 4)
- Create consent schema
- Build consent API
- Add consent checks to data access
-
Phase 5: Compliance Documentation (Week 5)
- Document all security controls
- Create incident response plan
- Prepare for HIPAA audit
Documentation
docs/compliance/hipaa-compliance-checklist.mddocs/security/encryption.mddocs/security/audit-logging.mddocs/security/incident-response.mddocs/compliance/data-retention.md
Status
Open
Related Issues
- Issue Authentication & Authorization Service #5: Authentication & Authorization
- Issue Shared Libraries Package Setup #6: Shared Libraries
- Issue Monitoring & Observability Setup #8: Monitoring & Observability