Sensitive data encryption processing
The Importance of Encrypting Sensitive Data
In modern web applications, sensitive data is ubiquitous. User passwords, ID numbers, bank card information, medical records, and more require strict protection. Koa2, as the next-generation web framework for Node.js, provides a flexible middleware mechanism, allowing data encryption to be elegantly integrated into the request-response flow. Unencrypted sensitive data, once leaked, can lead to severe security incidents and legal risks.
Common Types of Sensitive Data
Sensitive data that requires encryption typically includes:
- User authentication information: passwords, API keys, OAuth tokens
- Personal identity information: names, ID numbers, phone numbers
- Financial data: bank card numbers, transaction records, account balances
- Medical and health data: medical records, test reports, prescription information
- Business secrets: contract details, customer lists, strategic plans
// Example: Sensitive data structure
const sensitiveData = {
username: 'user123',
password: 'plaintextPassword', // Needs encryption
creditCard: {
number: '4111111111111111', // Needs encryption
expiry: '12/25',
cvv: '123' // Needs encryption
},
ssn: '123-45-6789' // Needs encryption
};
Choosing Encryption Algorithms
Common encryption algorithms in Koa2 applications can be divided into three categories:
Symmetric Encryption
AES is the most commonly used option, where the same key is used for encryption and decryption:
const crypto = require('crypto');
const algorithm = 'aes-256-cbc';
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
function encrypt(text) {
let cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return { iv: iv.toString('hex'), encryptedData: encrypted.toString('hex') };
}
function decrypt(text) {
let iv = Buffer.from(text.iv, 'hex');
let encryptedText = Buffer.from(text.encryptedData, 'hex');
let decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
Asymmetric Encryption
RSA is suitable for key exchange scenarios:
const { generateKeyPairSync, publicEncrypt, privateDecrypt } = require('crypto');
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 2048,
});
const encrypted = publicEncrypt(
publicKey,
Buffer.from('Sensitive data')
);
const decrypted = privateDecrypt(
privateKey,
encrypted
);
Hashing Algorithms
Used for password storage, bcrypt is recommended:
const bcrypt = require('bcrypt');
const saltRounds = 10;
async function hashPassword(password) {
return await bcrypt.hash(password, saltRounds);
}
async function checkPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
Implementing Encryption Middleware in Koa2
In Koa2, sensitive data can be uniformly processed through middleware:
Request Data Encryption
const encryptMiddleware = async (ctx, next) => {
await next();
if (ctx.body && ctx.body.sensitiveData) {
ctx.body.sensitiveData = encrypt(ctx.body.sensitiveData);
}
};
app.use(encryptMiddleware);
Response Data Decryption
const decryptMiddleware = async (ctx, next) => {
if (ctx.request.body && ctx.request.body.encryptedData) {
ctx.request.body = decrypt(ctx.request.body.encryptedData);
}
await next();
};
app.use(decryptMiddleware);
Complete Example
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const { encrypt, decrypt } = require('./crypto-utils');
const app = new Koa();
// Decrypt request body
app.use(async (ctx, next) => {
if (ctx.request.body && ctx.request.body.__encrypted) {
try {
ctx.request.body = JSON.parse(
decrypt(ctx.request.body.__encrypted)
);
} catch (err) {
ctx.throw(400, 'Invalid encrypted data');
}
}
await next();
});
// Business routes
app.use(bodyParser());
app.use(async ctx => {
if (ctx.method === 'POST' && ctx.path === '/secure-data') {
// Process decrypted sensitive data
const { creditCard } = ctx.request.body;
// Business processing...
// Return encrypted response
ctx.body = {
__encrypted: encrypt(JSON.stringify({
status: 'success',
maskedCard: `****-****-****-${creditCard.number.slice(-4)}`
}))
};
}
});
// Encrypt response
app.use(async (ctx, next) => {
await next();
if (ctx.body && ctx.body.__encrypted) {
// Already encrypted, skip further processing
return;
}
if (ctx.body && ctx.body.encrypt === true) {
ctx.body = {
__encrypted: encrypt(JSON.stringify(ctx.body))
};
ctx.set('Content-Type', 'application/json');
}
});
Database-Level Encryption Strategies
Field-Level Encryption
// Mongoose example
const userSchema = new mongoose.Schema({
username: String,
ssn: {
type: String,
get: decrypt,
set: encrypt,
required: true
}
});
// Explicitly include encrypted fields when querying
User.find().select('+ssn');
Transparent Data Encryption (TDE)
Most database systems support tablespace or full-database encryption:
-- MySQL example
CREATE TABLE patients (
id INT PRIMARY KEY,
name VARCHAR(100),
medical_record TEXT ENCRYPTED WITH 'AES-256'
);
Protection During Transmission
Enforcing HTTPS
Enabling HTTPS in Koa2:
const https = require('https');
const fs = require('fs');
const Koa = require('koa');
const app = new Koa();
const options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
};
https.createServer(options, app.callback()).listen(443);
Setting Security Headers
const helmet = require('koa-helmet');
app.use(helmet());
Best Practices for Key Management
Key Storage Solutions
// Using environment variables + key management services
const { KMS } = require('aws-sdk');
const kms = new KMS();
async function getEncryptionKey() {
if (process.env.ENV === 'production') {
const data = await kms.decrypt({
CiphertextBlob: Buffer.from(process.env.ENCRYPTION_KEY, 'base64')
}).promise();
return data.Plaintext;
}
return Buffer.from(process.env.DEV_ENCRYPTION_KEY, 'hex');
}
Key Rotation Strategies
// Supporting multiple key versions
function decryptWithKeyRotation(encryptedData) {
for (const keyVersion of [process.env.KEY_V2, process.env.KEY_V1]) {
try {
return decrypt(encryptedData, keyVersion);
} catch (e) {
continue;
}
}
throw new Error('Decryption failed with all keys');
}
Balancing Performance and Security
Encryption operations incur performance overhead and require careful optimization:
Selective Encryption
function needsEncryption(field) {
const sensitiveFields = ['password', 'ssn', 'creditCard'];
return sensitiveFields.includes(field);
}
app.use(async (ctx, next) => {
await next();
if (ctx.body) {
for (const key in ctx.body) {
if (needsEncryption(key)) {
ctx.body[key] = encrypt(ctx.body[key]);
}
}
}
});
Caching Encryption Results
const NodeCache = require('node-cache');
const cryptoCache = new NodeCache({ stdTTL: 600 });
function cachedEncrypt(data) {
const hash = createHash('sha256').update(data).digest('hex');
if (cryptoCache.has(hash)) {
return cryptoCache.get(hash);
}
const encrypted = encrypt(data);
cryptoCache.set(hash, encrypted);
return encrypted;
}
Compliance Requirements
Different industries have specific encryption standards:
GDPR Requirements
- Personal data must be encrypted at rest and in transit
- Secure decryption is required when implementing data subject access rights
- Key destruction must be ensured during data erasure
HIPAA Requirements
- Medical data must be encrypted both at rest and in transit
- All encryption/decryption operations must be logged
- Regular audits of encryption scheme effectiveness are required
// Audit logging middleware
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
auditLog({
timestamp: new Date(),
method: ctx.method,
path: ctx.path,
status: ctx.status,
duration: ms,
encryptedFields: Object.keys(ctx.request.body).filter(needsEncryption)
});
});
Common Issues and Solutions
Searching Encrypted Data
Using deterministic encryption or blind indexes:
// Creating a hash index for encrypted fields
function createSearchIndex(value) {
return createHash('sha256')
.update(value + process.env.INDEX_SALT)
.digest('hex');
}
// When querying
User.find({
ssnIndex: createSearchIndex(querySSN)
});
Paginating Encrypted Data
// In-memory pagination solution
async function getPaginatedEncryptedData(page, size) {
const allData = await Data.find().select('+encryptedField');
const decrypted = allData.map(item => ({
...item.toObject(),
encryptedField: decrypt(item.encryptedField)
}));
return decrypted.slice((page - 1) * size, page * size);
}
Encryption in Microservice Architectures
In microservice environments, inter-service communication also requires encryption:
JWE Tokens
const { JWK, JWE } = require('node-jose');
const keystore = JWK.createKeyStore();
const key = await keystore.generate('RSA', 2048, { alg: 'RSA-OAEP-256' });
async function createJWE(payload) {
return await JWE.createEncrypt({ format: 'compact' }, key)
.update(JSON.stringify(payload))
.final();
}
async function decryptJWE(token) {
const result = await JWE.createDecrypt(keystore).decrypt(token);
return JSON.parse(result.payload.toString());
}
Service Mesh Encryption
# Istio TLS configuration example
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: encrypt-data
spec:
host: data-service
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:请求频率限制与防刷
下一篇:JWT 认证安全实践