OWASP Secure Coding Practices Guide
Master OWASP secure coding practices to prevent vulnerabilities and build secure applications. Learn how to protect against the OWASP Top 10 threats and common attack vectors.
Why Secure Coding Matters
Security vulnerabilities can lead to data breaches, financial losses, and reputational damage. According to recent studies, 84% of security breaches involve application-layer attacks, making secure coding practices essential for every developer.
This guide covers the most critical security practices based on the OWASP Top 10 and industry best practices. Each section includes practical examples and code snippets you can implement immediately.
OWASP Top 10 Security Risks
Broken Access Control
Restrictions on authenticated users are not properly enforced
Cryptographic Failures
Sensitive data exposed due to lack of encryption
Injection
Untrusted data sent to interpreter as part of command/query
Insecure Design
Missing or ineffective security controls in design
Security Misconfiguration
Incomplete or ad-hoc configurations, default settings
Vulnerable Components
Using components with known vulnerabilities
Authentication Failures
Broken authentication and session management
Data Integrity Failures
Assumptions about software updates, CI/CD pipelines
Security Logging Failures
Insufficient logging and monitoring
Server-Side Request Forgery
Web app fetches remote resource without validating URL
Core Security Practices
1. Input Validation & Sanitization
Always validate and sanitize user input to prevent injection attacks. Never trust data from users, APIs, or any external source.
Bad Practice
// Vulnerable to SQL injection
const query = `SELECT * FROM users WHERE email = '${email}'`;
db.query(query);
// Vulnerable to XSS
element.innerHTML = userInput;Good Practice
// Use parameterized queries
const query = 'SELECT * FROM users WHERE email = ?';
db.query(query, [email]);
// Sanitize output
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
// Validate input format
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}2. Strong Authentication
Implement secure authentication with proper password hashing, session management, and multi-factor authentication.
Bad Practice
// Storing passwords in plain text
user.password = password;
// Weak password requirements
if (password.length >= 6) { /* accept */ }
// Using MD5/SHA1 for passwords
const hash = md5(password);Good Practice
import bcrypt from 'bcrypt';
// Hash passwords with bcrypt
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(password, saltRounds);
// Strong password validation
function validatePassword(password) {
const minLength = 12;
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumbers = /\d/.test(password);
const hasSpecialChar = /[!@#$%^&*]/.test(password);
return password.length >= minLength &&
hasUpperCase && hasLowerCase &&
hasNumbers && hasSpecialChar;
}
// Implement rate limiting
const loginAttempts = new Map();
function checkRateLimit(ip) {
const attempts = loginAttempts.get(ip) || 0;
if (attempts >= 5) {
throw new Error('Too many login attempts');
}
loginAttempts.set(ip, attempts + 1);
}3. Secure Data Storage
Encrypt sensitive data at rest and in transit. Use environment variables for secrets, never hardcode them.
Bad Practice
// Hardcoded secrets
const API_KEY = 'sk_live_1234567890abcdef';
const DB_PASSWORD = 'MyPassword123';
// Storing sensitive data in plain text
await db.save({ ssn: '123-45-6789' });Good Practice
// Use environment variables
const API_KEY = process.env.API_KEY;
const DB_PASSWORD = process.env.DB_PASSWORD;
// Encrypt sensitive data
import { encrypt, decrypt } from './encryption';
async function saveSensitiveData(data) {
const encryptedSSN = encrypt(data.ssn, process.env.ENCRYPTION_KEY);
await db.save({ ssn: encryptedSSN });
}
// Use HTTPS for all communications
const options = {
cert: fs.readFileSync('cert.pem'),
key: fs.readFileSync('key.pem')
};
https.createServer(options, app);4. Implement Proper Access Control
Enforce principle of least privilege and implement role-based access control (RBAC).
Implementation Example
// Middleware for role-based access control
function requireRole(allowedRoles) {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: 'Unauthorized' });
}
if (!allowedRoles.includes(req.user.role)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
}
// Usage
app.delete('/api/users/:id',
requireRole(['admin']),
async (req, res) => {
// Only admins can delete users
await deleteUser(req.params.id);
res.json({ success: true });
}
);
// Verify ownership
async function requireOwnership(req, res, next) {
const resource = await getResource(req.params.id);
if (resource.userId !== req.user.id && req.user.role !== 'admin') {
return res.status(403).json({ error: 'Access denied' });
}
next();
}5. Security Logging & Monitoring
Implement comprehensive logging for security events and monitor for suspicious activity.
Security Event Logging
import winston from 'winston';
const securityLogger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({
filename: 'security.log'
})
]
});
// Log security events
function logSecurityEvent(event, user, metadata) {
securityLogger.info({
timestamp: new Date().toISOString(),
event,
userId: user?.id,
ip: metadata.ip,
userAgent: metadata.userAgent,
...metadata
});
}
// Usage
app.post('/login', async (req, res) => {
try {
const user = await authenticate(req.body);
logSecurityEvent('LOGIN_SUCCESS', user, {
ip: req.ip,
userAgent: req.get('user-agent')
});
res.json({ token: generateToken(user) });
} catch (error) {
logSecurityEvent('LOGIN_FAILURE', null, {
ip: req.ip,
email: req.body.email,
reason: error.message
});
res.status(401).json({ error: 'Invalid credentials' });
}
});Security Checklist
Code Security
- Validate all user inputs
- Use parameterized queries
- Implement CSRF protection
- Set secure HTTP headers
- Use Content Security Policy
- Enable HTTPS everywhere
Authentication & Access
- Hash passwords with bcrypt
- Implement MFA
- Use secure session management
- Apply rate limiting
- Enforce strong passwords
- Implement RBAC
Data Protection
- Encrypt sensitive data
- Use environment variables
- Implement data retention policies
- Secure file uploads
- Sanitize user output
- Regular security backups
Monitoring & Response
- Log security events
- Monitor for anomalies
- Set up alerts
- Regular security audits
- Keep dependencies updated
- Have incident response plan
Security Tools & Resources
Automate Security Reviews with CodeRaptor
Let CodeRaptor automatically scan your code for security vulnerabilities. Catch issues before they reach production.
Start Free Trial