Skip to main content

Security Overview

Security is a fundamental aspect of any application. This guide covers security best practices, common vulnerabilities, and how to implement robust security measures in Solverhood applications.

Security Principles

Core Principles

  • Defense in Depth: Multiple layers of security controls
  • Principle of Least Privilege: Grant minimum necessary permissions
  • Fail Securely: Default to secure state when errors occur
  • Security by Design: Build security into the development process
  • Regular Updates: Keep dependencies and systems updated

Security Model

Our security model follows the CIA triad:

  • Confidentiality: Protect sensitive data from unauthorized access
  • Integrity: Ensure data accuracy and consistency
  • Availability: Maintain system availability for authorized users

Common Security Vulnerabilities

1. Injection Attacks

SQL Injection Prevention

// ❌ Vulnerable - Direct string concatenation
const query = `SELECT * FROM users WHERE id = ${userId}`;

// ✅ Secure - Parameterized queries
const query = 'SELECT * FROM users WHERE id = $1';
const result = await db.query(query, [userId]);

// ✅ Secure - Using an ORM
const user = await User.findByPk(userId);

NoSQL Injection Prevention

// ❌ Vulnerable - Direct object injection
const user = await User.findOne({ email: req.body.email });

// ✅ Secure - Validate and sanitize input
const { email } = req.body;
if (!isValidEmail(email)) {
throw new Error('Invalid email format');
}
const user = await User.findOne({ email });

2. Cross-Site Scripting (XSS)

Prevention Strategies

// ❌ Vulnerable - Direct HTML injection
app.get('/search', (req, res) => {
const query = req.query.q;
res.send(`<h1>Search results for: ${query}</h1>`);
});

// ✅ Secure - HTML escaping
const escapeHtml = (text) => {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
};

app.get('/search', (req, res) => {
const query = escapeHtml(req.query.q);
res.send(`<h1>Search results for: ${query}</h1>`);
});

// ✅ Secure - Using template engines with auto-escaping
app.get('/search', (req, res) => {
res.render('search', { query: req.query.q });
});

3. Cross-Site Request Forgery (CSRF)

CSRF Protection

const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });

// Apply CSRF protection to all routes
app.use(csrfProtection);

// Generate CSRF token for forms
app.get('/form', (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});

// Verify CSRF token on form submission
app.post('/submit', csrfProtection, (req, res) => {
// Process form data
res.json({ success: true });
});

4. Authentication Vulnerabilities

Secure Password Handling

const bcrypt = require('bcrypt');

// ✅ Secure password hashing
async function hashPassword(password) {
const saltRounds = 12;
return await bcrypt.hash(password, saltRounds);
}

// ✅ Secure password verification
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}

// ✅ Password strength validation
function validatePassword(password) {
const minLength = 8;
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumbers = /\d/.test(password);
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);

if (password.length < minLength) {
throw new Error('Password must be at least 8 characters long');
}
if (!hasUpperCase || !hasLowerCase) {
throw new Error('Password must contain both uppercase and lowercase letters');
}
if (!hasNumbers) {
throw new Error('Password must contain at least one number');
}
if (!hasSpecialChar) {
throw new Error('Password must contain at least one special character');
}
}

Authentication & Authorization

1. JWT Security

Secure JWT Implementation

const jwt = require('jsonwebtoken');

// ✅ Secure JWT configuration
const jwtConfig = {
secret: process.env.JWT_SECRET,
expiresIn: '15m', // Short expiration
issuer: 'solverhood',
audience: 'solverhood-users',
};

// Generate JWT
function generateToken(user) {
return jwt.sign(
{
userId: user.id,
email: user.email,
role: user.role,
},
jwtConfig.secret,
{
expiresIn: jwtConfig.expiresIn,
issuer: jwtConfig.issuer,
audience: jwtConfig.audience,
}
);
}

// Verify JWT
function verifyToken(token) {
try {
return jwt.verify(token, jwtConfig.secret, {
issuer: jwtConfig.issuer,
audience: jwtConfig.audience,
});
} catch (error) {
throw new Error('Invalid token');
}
}

2. Role-Based Access Control (RBAC)

// Define roles and permissions
const roles = {
ADMIN: ['read', 'write', 'delete', 'manage_users'],
MODERATOR: ['read', 'write', 'moderate'],
USER: ['read', 'write'],
GUEST: ['read'],
};

// Authorization middleware
function authorize(requiredPermission) {
return (req, res, next) => {
const userRole = req.user.role;
const userPermissions = roles[userRole] || [];

if (!userPermissions.includes(requiredPermission)) {
return res.status(403).json({ error: 'Insufficient permissions' });
}

next();
};
}

// Usage
app.delete('/api/users/:id', authenticateToken, authorize('manage_users'), deleteUser);

Data Protection

1. Input Validation

const { body, validationResult } = require('express-validator');

// Comprehensive input validation
const validateUser = [
body('email').isEmail().normalizeEmail().withMessage('Valid email is required'),

body('password')
.isLength({ min: 8 })
.matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])/)
.withMessage('Password must be at least 8 characters with uppercase, lowercase, number, and special character'),

body('name').trim().isLength({ min: 2, max: 50 }).escape().withMessage('Name must be between 2 and 50 characters'),

(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
},
];

2. Data Encryption

const crypto = require('crypto');

// Encrypt sensitive data
function encryptData(data, key) {
const algorithm = 'aes-256-gcm';
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipher(algorithm, key);

let encrypted = cipher.update(data, 'utf8', 'hex');
encrypted += cipher.final('hex');

const authTag = cipher.getAuthTag();

return {
encrypted,
iv: iv.toString('hex'),
authTag: authTag.toString('hex'),
};
}

// Decrypt sensitive data
function decryptData(encryptedData, key) {
const algorithm = 'aes-256-gcm';
const decipher = crypto.createDecipher(algorithm, key);

decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));

let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');

return decrypted;
}

API Security

1. Rate Limiting

const rateLimit = require('express-rate-limit');

// General rate limiting
const generalLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP, please try again later.',
standardHeaders: true,
legacyHeaders: false,
});

// Stricter rate limiting for authentication
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // limit each IP to 5 requests per windowMs
message: 'Too many authentication attempts, please try again later.',
skipSuccessfulRequests: true,
});

app.use('/api/', generalLimiter);
app.use('/api/auth', authLimiter);

2. API Key Management

// API key validation middleware
function validateApiKey(req, res, next) {
const apiKey = req.headers['x-api-key'];

if (!apiKey) {
return res.status(401).json({ error: 'API key required' });
}

// Validate API key format
if (!/^sk_[a-zA-Z0-9]{32}$/.test(apiKey)) {
return res.status(401).json({ error: 'Invalid API key format' });
}

// Check if API key exists and is active
const key = await ApiKey.findOne({ key: apiKey, active: true });
if (!key) {
return res.status(401).json({ error: 'Invalid or inactive API key' });
}

// Check rate limits
const usage = await checkApiKeyUsage(key.id);
if (usage.exceeded) {
return res.status(429).json({ error: 'Rate limit exceeded' });
}

req.apiKey = key;
next();
}

Infrastructure Security

1. Environment Variables

// Secure environment variable management
const requiredEnvVars = ['DATABASE_URL', 'JWT_SECRET', 'API_SECRET_KEY', 'REDIS_URL'];

// Validate required environment variables
function validateEnvironment() {
const missing = requiredEnvVars.filter((varName) => !process.env[varName]);

if (missing.length > 0) {
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
}

// Validate JWT secret strength
if (process.env.JWT_SECRET.length < 32) {
throw new Error('JWT_SECRET must be at least 32 characters long');
}
}

// Call validation on startup
validateEnvironment();

2. Security Headers

const helmet = require('helmet');

// Comprehensive security headers
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", 'data:', 'https:'],
connectSrc: ["'self'"],
fontSrc: ["'self'"],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true,
},
noSniff: true,
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
})
);

Security Testing

1. Automated Security Testing

// Security test suite
describe('Security Tests', () => {
test('should prevent SQL injection', async () => {
const maliciousInput = "'; DROP TABLE users; --";

const response = await request(app).get('/api/users').query({ search: maliciousInput });

expect(response.status).not.toBe(500);
expect(response.body).not.toContain('DROP TABLE');
});

test('should prevent XSS attacks', async () => {
const maliciousInput = '<script>alert("xss")</script>';

const response = await request(app).post('/api/comments').send({ content: maliciousInput });

expect(response.body.content).not.toContain('<script>');
});

test('should enforce rate limiting', async () => {
const requests = Array(101)
.fill()
.map(() => request(app).get('/api/data'));

const responses = await Promise.all(requests);
const rateLimited = responses.filter((r) => r.status === 429);

expect(rateLimited.length).toBeGreaterThan(0);
});
});

2. Dependency Scanning

{
"scripts": {
"security:audit": "npm audit",
"security:fix": "npm audit fix",
"security:check": "snyk test",
"security:monitor": "snyk monitor"
},
"devDependencies": {
"snyk": "^1.1000.0"
}
}

Incident Response

1. Security Incident Plan

// Security incident logging
const securityLogger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [new winston.transports.File({ filename: 'security.log' })],
});

// Log security events
function logSecurityEvent(event, details) {
securityLogger.info('Security Event', {
timestamp: new Date().toISOString(),
event,
details,
ip: req.ip,
userAgent: req.get('User-Agent'),
userId: req.user?.id,
});
}

// Usage
app.post('/api/login', async (req, res) => {
try {
const user = await authenticateUser(req.body);
if (!user) {
logSecurityEvent('failed_login', { email: req.body.email });
return res.status(401).json({ error: 'Invalid credentials' });
}
// ... success logic
} catch (error) {
logSecurityEvent('login_error', { error: error.message });
res.status(500).json({ error: 'Authentication error' });
}
});

Compliance

1. GDPR Compliance

// Data privacy utilities
class DataPrivacy {
static async anonymizeUser(userId) {
const user = await User.findByPk(userId);
if (!user) return;

// Anonymize personal data
await user.update({
email: `deleted_${Date.now()}@deleted.com`,
name: 'Deleted User',
phone: null,
address: null,
});

// Log the action
await PrivacyLog.create({
action: 'anonymize',
userId,
timestamp: new Date(),
});
}

static async exportUserData(userId) {
const user = await User.findByPk(userId, {
include: [UserProjects, UserSettings],
});

return {
personalData: {
name: user.name,
email: user.email,
createdAt: user.createdAt,
},
projects: user.UserProjects,
settings: user.UserSettings,
};
}
}

Best Practices

1. Development Security

  • Code Review: All code changes must be reviewed for security
  • Dependency Management: Regularly update dependencies
  • Secret Management: Use secure secret management systems
  • Environment Separation: Separate development, staging, and production

2. Operational Security

  • Access Control: Implement least privilege access
  • Monitoring: Monitor for security events and anomalies
  • Backup Security: Encrypt backups and test restoration
  • Incident Response: Have a documented incident response plan

3. User Security

  • Multi-Factor Authentication: Implement MFA for sensitive operations
  • Session Management: Implement secure session handling
  • Password Policies: Enforce strong password requirements
  • Account Lockout: Implement account lockout after failed attempts

Next Steps

  • Authentication Security - Coming soon
  • API Security - Coming soon
  • Data Protection - Coming soon
  • Incident Response - Coming soon

Resources