Implementing Secure Data Storage
Implementing Secure Data Storage
Secure storage goes beyond basic encryption to encompass access controls, audit logging, backup strategies, and incident response. GDPR Article 32 requires "appropriate technical and organisational measures" considering the state of the art, costs, and risks. This technology-neutral approach allows flexibility but requires careful security assessment and implementation.
Encryption at rest protects data from unauthorized access if storage media is compromised. However, encryption alone isn't sufficient. Key management becomes critical – encrypted data is only as secure as its decryption keys. Hardware security modules (HSMs) or key management services provide secure key storage and rotation. Application-level encryption enables fine-grained control but requires careful implementation to avoid vulnerabilities.
// Secure data storage implementation
class SecureDataStorage {
constructor() {
this.encryptionAlgorithm = 'aes-256-gcm';
this.keyDerivationIterations = 100000;
this.auditLogger = new AuditLogger();
}
// Store data with multiple security layers
async storeSecurely(data, metadata) {
try {
// Generate unique document ID
const documentId = this.generateDocumentId();
// Classify data sensitivity
const classification = this.classifyData(data);
// Apply appropriate encryption
const encryptedData = await this.encryptData(data, classification);
// Add integrity check
const integrityHash = await this.calculateIntegrityHash(encryptedData);
// Store with access controls
const storageRecord = {
id: documentId,
data: encryptedData,
metadata: {
...metadata,
classification,
integrityHash,
createdAt: new Date().toISOString(),
version: 1,
accessControl: this.generateAccessControl(classification)
}
};
// Store in appropriate location based on classification
const storageLocation = this.selectStorageLocation(classification);
await storageLocation.store(storageRecord);
// Log access
await this.auditLogger.log({
action: 'data_stored',
documentId,
userId: metadata.userId,
classification,
timestamp: new Date().toISOString()
});
// Backup if required
if (classification.requiresBackup) {
await this.backupData(storageRecord);
}
return { success: true, documentId };
} catch (error) {
await this.handleStorageError(error, data, metadata);
throw error;
}
}
// Multi-layer encryption based on data sensitivity
async encryptData(data, classification) {
if (classification.level === 'public') {
return data; // No encryption needed
}
// Get appropriate key based on classification
const encryptionKey = await this.getEncryptionKey(classification);
// Serialize data
const serialized = JSON.stringify(data);
const dataBuffer = Buffer.from(serialized, 'utf8');
// Generate IV
const iv = crypto.randomBytes(16);
// Encrypt
const cipher = crypto.createCipheriv(this.encryptionAlgorithm, encryptionKey, iv);
const encrypted = Buffer.concat([
cipher.update(dataBuffer),
cipher.final()
]);
const authTag = cipher.getAuthTag();
// Additional encryption layer for highly sensitive data
if (classification.level === 'highly_sensitive') {
const doubleEncrypted = await this.addEncryptionLayer(encrypted, classification);
return {
data: doubleEncrypted.toString('base64'),
iv: iv.toString('base64'),
authTag: authTag.toString('base64'),
algorithm: this.encryptionAlgorithm,
doubleDncrypted: true
};
}
return {
data: encrypted.toString('base64'),
iv: iv.toString('base64'),
authTag: authTag.toString('base64'),
algorithm: this.encryptionAlgorithm
};
}
// Classify data sensitivity
classifyData(data) {
const classification = {
level: 'internal',
requiresEncryption: true,
requiresBackup: true,
retentionClass: 'standard',
accessLevel: 'restricted'
};
// Check for highly sensitive data
const sensitiveFfields = ['ssn', 'creditCard', 'bankAccount', 'medicalRecord'];
const hasSensitiveData = Object.keys(data).some(key =>
sensitiveFfields.some(field => key.toLowerCase().includes(field))
);
if (hasSensitiveData) {
classification.level = 'highly_sensitive';
classification.accessLevel = 'highly_restricted';
classification.retentionClass = 'sensitive';
}
// Check for PII
const piiFields = ['email', 'phone', 'address', 'dateOfBirth'];
const hasPII = Object.keys(data).some(key =>
piiFields.some(field => key.toLowerCase().includes(field))
);
if (hasPII) {
classification.level = classification.level || 'confidential';
classification.requiresEncryption = true;
}
return classification;
}
// Generate access control rules
generateAccessControl(classification) {
const acl = {
owner: 'system',
permissions: []
};
switch (classification.level) {
case 'highly_sensitive':
acl.permissions = [
{ role: 'data_protection_officer', access: ['read'] },
{ role: 'security_admin', access: ['read', 'audit'] },
{ role: 'system', access: ['read', 'write', 'delete'] }
];
break;
case 'confidential':
acl.permissions = [
{ role: 'admin', access: ['read', 'write'] },
{ role: 'support_tier2', access: ['read'] },
{ role: 'system', access: ['read', 'write', 'delete'] }
];
break;
default:
acl.permissions = [
{ role: 'authenticated', access: ['read'] },
{ role: 'admin', access: ['read', 'write', 'delete'] }
];
}
return acl;
}
// Retrieve data with access control
async retrieveSecurely(documentId, userId, purpose) {
try {
// Verify access permission
const hasAccess = await this.verifyAccess(documentId, userId, purpose);
if (!hasAccess) {
throw new Error('Access denied');
}
// Retrieve encrypted data
const storageRecord = await this.retrieveStorageRecord(documentId);
// Verify integrity
const integrityValid = await this.verifyIntegrity(storageRecord);
if (!integrityValid) {
throw new Error('Data integrity check failed');
}
// Decrypt data
const decryptedData = await this.decryptData(
storageRecord.data,
storageRecord.metadata.classification
);
// Log access
await this.auditLogger.log({
action: 'data_accessed',
documentId,
userId,
purpose,
timestamp: new Date().toISOString()
});
// Apply any field-level access controls
const filteredData = this.applyFieldLevelAccess(
decryptedData,
userId,
storageRecord.metadata.classification
);
return filteredData;
} catch (error) {
await this.auditLogger.log({
action: 'data_access_failed',
documentId,
userId,
error: error.message,
timestamp: new Date().toISOString()
});
throw error;
}
}
}