Security
Implement robust security measures in MatsushibaDB to protect your data and applications from threats and vulnerabilities.Authentication
User Authentication
Copy
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const MatsushibaDB = require('matsushibadb');
const db = new MatsushibaDB('app.db');
// User registration with password hashing
async function registerUser(userData) {
try {
// Hash password
const saltRounds = 12;
const passwordHash = await bcrypt.hash(userData.password, saltRounds);
// Store user
const result = db.run(`
INSERT INTO users (username, email, password_hash, created_at)
VALUES (?, ?, ?, CURRENT_TIMESTAMP)
`, [userData.username, userData.email, passwordHash]);
return {
success: true,
userId: result.lastInsertRowid,
message: 'User registered successfully'
};
} catch (error) {
if (error.message.includes('UNIQUE constraint failed')) {
return { success: false, error: 'Username or email already exists' };
}
throw error;
}
}
// User login with password verification
async function loginUser(credentials) {
try {
const user = db.get(`
SELECT id, username, email, password_hash, status
FROM users
WHERE username = ? OR email = ?
`, [credentials.username, credentials.username]);
if (!user) {
return { success: false, error: 'Invalid credentials' };
}
if (user.status !== 'active') {
return { success: false, error: 'Account is not active' };
}
// Verify password
const isValidPassword = await bcrypt.compare(credentials.password, user.password_hash);
if (!isValidPassword) {
return { success: false, error: 'Invalid credentials' };
}
// Generate JWT token
const token = jwt.sign(
{
userId: user.id,
username: user.username,
email: user.email
},
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
// Update last login
db.run('UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?', [user.id]);
return {
success: true,
token: token,
user: {
id: user.id,
username: user.username,
email: user.email
}
};
} catch (error) {
throw error;
}
}
// Token verification middleware
function verifyToken(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
return res.status(401).json({ error: 'Invalid token' });
}
}
Multi-Factor Authentication (MFA)
Copy
const speakeasy = require('speakeasy');
const QRCode = require('qrcode');
// Enable MFA for user
function enableMFA(userId) {
try {
// Generate secret
const secret = speakeasy.generateSecret({
name: 'MatsushibaDB App',
issuer: 'MatsushibaDB',
length: 32
});
// Store secret in database
db.run(`
INSERT OR REPLACE INTO user_mfa (user_id, secret, enabled, created_at)
VALUES (?, ?, 0, CURRENT_TIMESTAMP)
`, [userId, secret.base32]);
// Generate QR code
const qrCodeUrl = QRCode.toDataURL(secret.otpauth_url);
return {
success: true,
secret: secret.base32,
qrCode: qrCodeUrl,
manualEntryKey: secret.base32
};
} catch (error) {
throw error;
}
}
// Verify MFA token
function verifyMFAToken(userId, token) {
try {
const mfaRecord = db.get(`
SELECT secret FROM user_mfa
WHERE user_id = ? AND enabled = 1
`, [userId]);
if (!mfaRecord) {
return { success: false, error: 'MFA not enabled' };
}
const verified = speakeasy.totp.verify({
secret: mfaRecord.secret,
encoding: 'base32',
token: token,
window: 2 // Allow 2 time steps before/after
});
if (verified) {
// Log successful MFA verification
db.run(`
INSERT INTO security_logs (user_id, event_type, description, ip_address)
VALUES (?, ?, ?, ?)
`, [userId, 'mfa_success', 'MFA verification successful', req.ip]);
return { success: true, message: 'MFA verified' };
} else {
// Log failed MFA attempt
db.run(`
INSERT INTO security_logs (user_id, event_type, description, ip_address)
VALUES (?, ?, ?, ?)
`, [userId, 'mfa_failure', 'MFA verification failed', req.ip]);
return { success: false, error: 'Invalid MFA token' };
}
} catch (error) {
throw error;
}
}
// Complete login with MFA
async function loginWithMFA(credentials, mfaToken) {
try {
// First verify credentials
const loginResult = await loginUser(credentials);
if (!loginResult.success) {
return loginResult;
}
// Check if MFA is enabled
const mfaEnabled = db.get(`
SELECT enabled FROM user_mfa WHERE user_id = ?
`, [loginResult.user.id]);
if (mfaEnabled && mfaEnabled.enabled) {
// Verify MFA token
const mfaResult = verifyMFAToken(loginResult.user.id, mfaToken);
if (!mfaResult.success) {
return mfaResult;
}
}
return loginResult;
} catch (error) {
throw error;
}
}
Authorization
Role-Based Access Control (RBAC)
Copy
// Create roles and permissions
function initializeRBAC() {
// Create roles
const roles = [
{ name: 'admin', description: 'Administrator with full access' },
{ name: 'moderator', description: 'Moderator with limited admin access' },
{ name: 'user', description: 'Regular user' },
{ name: 'guest', description: 'Guest user with read-only access' }
];
roles.forEach(role => {
db.run(`
INSERT OR IGNORE INTO roles (name, description, created_at)
VALUES (?, ?, CURRENT_TIMESTAMP)
`, [role.name, role.description]);
});
// Create permissions
const permissions = [
{ name: 'read_users', description: 'Read user data' },
{ name: 'write_users', description: 'Create/update users' },
{ name: 'delete_users', description: 'Delete users' },
{ name: 'read_posts', description: 'Read posts' },
{ name: 'write_posts', description: 'Create/update posts' },
{ name: 'delete_posts', description: 'Delete posts' },
{ name: 'moderate_content', description: 'Moderate content' },
{ name: 'admin_access', description: 'Full admin access' }
];
permissions.forEach(permission => {
db.run(`
INSERT OR IGNORE INTO permissions (name, description, created_at)
VALUES (?, ?, CURRENT_TIMESTAMP)
`, [permission.name, permission.description]);
});
// Assign permissions to roles
const rolePermissions = [
// Admin gets all permissions
{ role: 'admin', permissions: ['read_users', 'write_users', 'delete_users', 'read_posts', 'write_posts', 'delete_posts', 'moderate_content', 'admin_access'] },
// Moderator gets moderation and content permissions
{ role: 'moderator', permissions: ['read_users', 'read_posts', 'write_posts', 'moderate_content'] },
// User gets basic permissions
{ role: 'user', permissions: ['read_posts', 'write_posts'] },
// Guest gets read-only permissions
{ role: 'guest', permissions: ['read_posts'] }
];
rolePermissions.forEach(({ role, permissions }) => {
const roleId = db.get('SELECT id FROM roles WHERE name = ?', [role]).id;
permissions.forEach(permissionName => {
const permissionId = db.get('SELECT id FROM permissions WHERE name = ?', [permissionName]).id;
db.run(`
INSERT OR IGNORE INTO role_permissions (role_id, permission_id)
VALUES (?, ?)
`, [roleId, permissionId]);
});
});
}
// Assign role to user
function assignUserRole(userId, roleName) {
try {
const role = db.get('SELECT id FROM roles WHERE name = ?', [roleName]);
if (!role) {
return { success: false, error: 'Role not found' };
}
db.run(`
INSERT OR REPLACE INTO user_roles (user_id, role_id, assigned_at)
VALUES (?, ?, CURRENT_TIMESTAMP)
`, [userId, role.id]);
return { success: true, message: `Role ${roleName} assigned to user` };
} catch (error) {
throw error;
}
}
// Check user permission
function hasPermission(userId, permissionName) {
try {
const result = db.get(`
SELECT COUNT(*) as count
FROM user_roles ur
JOIN role_permissions rp ON ur.role_id = rp.role_id
JOIN permissions p ON rp.permission_id = p.id
WHERE ur.user_id = ? AND p.name = ?
`, [userId, permissionName]);
return result.count > 0;
} catch (error) {
return false;
}
}
// Authorization middleware
function requirePermission(permission) {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: 'Authentication required' });
}
if (!hasPermission(req.user.userId, permission)) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
next();
};
}
Data Encryption
Database-Level Encryption
Copy
const crypto = require('crypto');
// Encryption configuration
const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY || crypto.randomBytes(32);
const ALGORITHM = 'aes-256-gcm';
// Encrypt sensitive data
function encryptData(text) {
try {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipher(ALGORITHM, ENCRYPTION_KEY);
cipher.setAAD(Buffer.from('matsushiba-db', 'utf8'));
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return {
encrypted: encrypted,
iv: iv.toString('hex'),
authTag: authTag.toString('hex')
};
} catch (error) {
throw new Error('Encryption failed: ' + error.message);
}
}
// Decrypt sensitive data
function decryptData(encryptedData) {
try {
const decipher = crypto.createDecipher(ALGORITHM, ENCRYPTION_KEY);
decipher.setAAD(Buffer.from('matsushiba-db', 'utf8'));
decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
} catch (error) {
throw new Error('Decryption failed: ' + error.message);
}
}
// Store encrypted sensitive data
function storeSensitiveData(userId, sensitiveData) {
try {
const encrypted = encryptData(JSON.stringify(sensitiveData));
db.run(`
INSERT INTO sensitive_data (user_id, encrypted_data, iv, auth_tag, created_at)
VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP)
`, [userId, encrypted.encrypted, encrypted.iv, encrypted.authTag]);
return { success: true, message: 'Sensitive data stored securely' };
} catch (error) {
throw error;
}
}
// Retrieve and decrypt sensitive data
function getSensitiveData(userId) {
try {
const record = db.get(`
SELECT encrypted_data, iv, auth_tag
FROM sensitive_data
WHERE user_id = ?
`, [userId]);
if (!record) {
return { success: false, error: 'No sensitive data found' };
}
const decrypted = decryptData({
encrypted: record.encrypted_data,
iv: record.iv,
authTag: record.auth_tag
});
return {
success: true,
data: JSON.parse(decrypted)
};
} catch (error) {
throw error;
}
}
Security Monitoring
Audit Logging
Copy
// Security event logging
function logSecurityEvent(userId, eventType, description, metadata = {}) {
try {
db.run(`
INSERT INTO security_logs (
user_id, event_type, description, metadata,
ip_address, user_agent, created_at
) VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
`, [
userId,
eventType,
description,
JSON.stringify(metadata),
req?.ip || 'unknown',
req?.get('User-Agent') || 'unknown'
]);
} catch (error) {
console.error('Failed to log security event:', error);
}
}
// Failed login attempt tracking
function trackFailedLogin(username, ipAddress) {
try {
// Log failed attempt
logSecurityEvent(null, 'login_failed', `Failed login attempt for ${username}`, {
username: username,
ip_address: ipAddress
});
// Check for suspicious activity
const recentFailures = db.get(`
SELECT COUNT(*) as count
FROM security_logs
WHERE event_type = 'login_failed'
AND ip_address = ?
AND created_at > datetime('now', '-15 minutes')
`, [ipAddress]);
if (recentFailures.count >= 5) {
// Block IP temporarily
db.run(`
INSERT INTO blocked_ips (ip_address, reason, blocked_until)
VALUES (?, ?, datetime('now', '+1 hour'))
`, [ipAddress, 'Multiple failed login attempts']);
logSecurityEvent(null, 'ip_blocked', `IP ${ipAddress} blocked due to suspicious activity`);
}
} catch (error) {
console.error('Failed to track failed login:', error);
}
}
// Security monitoring dashboard
function getSecurityMetrics() {
try {
const metrics = {};
// Failed login attempts in last 24 hours
metrics.failedLogins = db.get(`
SELECT COUNT(*) as count
FROM security_logs
WHERE event_type = 'login_failed'
AND created_at > datetime('now', '-24 hours')
`).count;
// Active blocked IPs
metrics.blockedIPs = db.get(`
SELECT COUNT(*) as count
FROM blocked_ips
WHERE blocked_until > datetime('now')
`).count;
// MFA usage
metrics.mfaUsage = db.get(`
SELECT COUNT(*) as count
FROM security_logs
WHERE event_type = 'mfa_success'
AND created_at > datetime('now', '-24 hours')
`).count;
// Recent security events
metrics.recentEvents = db.all(`
SELECT event_type, description, created_at
FROM security_logs
WHERE created_at > datetime('now', '-1 hour')
ORDER BY created_at DESC
LIMIT 10
`);
return metrics;
} catch (error) {
throw error;
}
}
Security Best Practices
Input Validation and Sanitization
Copy
const validator = require('validator');
const xss = require('xss');
// Input validation
function validateInput(data, rules) {
const errors = [];
for (const [field, rule] of Object.entries(rules)) {
const value = data[field];
if (rule.required && (!value || value.trim() === '')) {
errors.push(`${field} is required`);
continue;
}
if (value) {
if (rule.type === 'email' && !validator.isEmail(value)) {
errors.push(`${field} must be a valid email`);
}
if (rule.type === 'password' && !validator.isStrongPassword(value)) {
errors.push(`${field} must be a strong password`);
}
if (rule.minLength && value.length < rule.minLength) {
errors.push(`${field} must be at least ${rule.minLength} characters`);
}
if (rule.maxLength && value.length > rule.maxLength) {
errors.push(`${field} must be no more than ${rule.maxLength} characters`);
}
}
}
return errors;
}
// Sanitize input
function sanitizeInput(input) {
if (typeof input === 'string') {
// Remove XSS
return xss(input, {
whiteList: {},
stripIgnoreTag: true,
stripIgnoreTagBody: ['script']
});
}
if (typeof input === 'object' && input !== null) {
const sanitized = {};
for (const [key, value] of Object.entries(input)) {
sanitized[key] = sanitizeInput(value);
}
return sanitized;
}
return input;
}
// Secure user creation
function createUserSecurely(userData) {
try {
// Validate input
const validationRules = {
username: { required: true, minLength: 3, maxLength: 50 },
email: { required: true, type: 'email' },
password: { required: true, type: 'password' }
};
const validationErrors = validateInput(userData, validationRules);
if (validationErrors.length > 0) {
return { success: false, errors: validationErrors };
}
// Sanitize input
const sanitizedData = sanitizeInput(userData);
// Hash password
const passwordHash = bcrypt.hashSync(sanitizedData.password, 12);
// Store user
const result = db.run(`
INSERT INTO users (username, email, password_hash, created_at)
VALUES (?, ?, ?, CURRENT_TIMESTAMP)
`, [sanitizedData.username, sanitizedData.email, passwordHash]);
return {
success: true,
userId: result.lastInsertRowid,
message: 'User created successfully'
};
} catch (error) {
throw error;
}
}
Security Configuration
Database Security Settings
Copy
-- Enable foreign key constraints
PRAGMA foreign_keys = ON;
-- Set secure journal mode
PRAGMA journal_mode = WAL;
-- Enable secure delete
PRAGMA secure_delete = ON;
-- Set synchronous mode for data integrity
PRAGMA synchronous = FULL;
-- Enable query-only mode for read operations
PRAGMA query_only = ON;
-- Set cache size for performance
PRAGMA cache_size = 2000;
-- Enable integrity check
PRAGMA integrity_check;
Security Tables Schema
Copy
-- Users table with security fields
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
status TEXT DEFAULT 'active' CHECK (status IN ('active', 'inactive', 'suspended', 'banned')),
failed_login_attempts INTEGER DEFAULT 0,
last_login DATETIME,
password_changed_at DATETIME DEFAULT CURRENT_TIMESTAMP,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Roles table
CREATE TABLE roles (
id INTEGER PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
description TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Permissions table
CREATE TABLE permissions (
id INTEGER PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
description TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- User roles junction table
CREATE TABLE user_roles (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
role_id INTEGER NOT NULL,
assigned_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
UNIQUE(user_id, role_id)
);
-- Role permissions junction table
CREATE TABLE role_permissions (
id INTEGER PRIMARY KEY,
role_id INTEGER NOT NULL,
permission_id INTEGER NOT NULL,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE,
UNIQUE(role_id, permission_id)
);
-- MFA table
CREATE TABLE user_mfa (
id INTEGER PRIMARY KEY,
user_id INTEGER UNIQUE NOT NULL,
secret TEXT NOT NULL,
enabled BOOLEAN DEFAULT 0,
backup_codes TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- Security logs table
CREATE TABLE security_logs (
id INTEGER PRIMARY KEY,
user_id INTEGER,
event_type TEXT NOT NULL,
description TEXT NOT NULL,
metadata TEXT,
ip_address TEXT,
user_agent TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
);
-- Blocked IPs table
CREATE TABLE blocked_ips (
id INTEGER PRIMARY KEY,
ip_address TEXT UNIQUE NOT NULL,
reason TEXT NOT NULL,
blocked_until DATETIME NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Sensitive data table
CREATE TABLE sensitive_data (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
encrypted_data TEXT NOT NULL,
iv TEXT,
auth_tag TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
Best Practices
1
Use Strong Authentication
Implement strong password policies, MFA, and secure session management.
2
Implement RBAC
Use role-based access control to limit user permissions appropriately.
3
Encrypt Sensitive Data
Encrypt sensitive data at rest and in transit using strong encryption algorithms.
4
Validate and Sanitize Input
Always validate and sanitize user input to prevent injection attacks.
5
Monitor Security Events
Implement comprehensive audit logging and security monitoring.
6
Use HTTPS
Always use HTTPS in production to encrypt data in transit.
7
Regular Security Updates
Keep all dependencies and systems updated with security patches.
8
Implement Rate Limiting
Use rate limiting to prevent brute force attacks and abuse.
Security is a critical aspect of any database application. Always implement multiple layers of security and regularly audit your security measures to ensure they remain effective.