## OWASP Top 10 - 2026 Edition
OWASP (Open Web Application Security Project) cập nhật danh sách 10 lỗ hổng bảo mật phổ biến nhất mỗi 3 năm. Phiên bản 2026 có một số thay đổi quan trọng về AI và supply chain.
## 1. Broken Access Control
### Vấn đề
Người dùng truy cập được resource không thuộc quyền của họ.
### Ví dụ lỗ hổng
\`\`\`typescript
// ❌ BAD: Không kiểm tra ownership
app.get('/api/documents/:id', async (req, res) => {
const doc = await db.documents.findById(req.params.id);
res.json(doc); // User có thể xem document của người khác!
});
\`\`\`
### Giải pháp
\`\`\`typescript
// ✅ GOOD: Kiểm tra ownership
app.get('/api/documents/:id', authMiddleware, async (req, res) => {
const doc = await db.documents.findById(req.params.id);
if (!doc) {
return res.status(404).json({ error: 'Not found' });
}
if (doc.userId !== req.user.id && !req.user.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
res.json(doc);
});
\`\`\`
### Best practices
- Dùng middleware kiểm tra quyền trước mọi route
- Implement RBAC (Role-Based Access Control)
- Test access control với nhiều user roles
## 2. Cryptographic Failures
### Vấn đề
Dữ liệu nhạy cảm không được mã hóa hoặc dùng thuật toán yếu.
### Ví dụ lỗ hổng
\`\`\`typescript
// ❌ BAD: Lưu password plain text
const user = {
email: '[email protected]',
password: 'mypassword123' // NGUY HIỂM!
};
\`\`\`
### Giải pháp
\`\`\`typescript
// ✅ GOOD: Hash password với bcrypt
import bcrypt from 'bcryptjs';
const hashedPassword = await bcrypt.hash(password, 12);
const user = {
email: '[email protected]',
passwordHash: hashedPassword
};
// Verify
const isValid = await bcrypt.compare(inputPassword, user.passwordHash);
\`\`\`
### Encryption cho sensitive data
\`\`\`typescript
import crypto from 'crypto';
const algorithm = 'aes-256-gcm';
const key = crypto.scryptSync(process.env.ENCRYPTION_KEY!, 'salt', 32);
function encrypt(text: string): string {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, key, iv);
const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);
const authTag = cipher.getAuthTag();
return \`\${iv.toString('hex')}:\${authTag.toString('hex')}:\${encrypted.toString('hex')}\`;
}
function decrypt(encrypted: string): string {
const [ivHex, authTagHex, encryptedHex] = encrypted.split(':');
const iv = Buffer.from(ivHex, 'hex');
const authTag = Buffer.from(authTagHex, 'hex');
const encryptedData = Buffer.from(encryptedHex, 'hex');
const decipher = crypto.createDecipheriv(algorithm, key, iv);
decipher.setAuthTag(authTag);
return decipher.update(encryptedData) + decipher.final('utf8');
}
\`\`\`
## 3. Injection (SQL, NoSQL, Command)
### SQL Injection
\`\`\`typescript
// ❌ BAD
const userId = req.query.id;
const user = await db.query(\`SELECT * FROM users WHERE id = \${userId}\`);
// Attacker: ?id=1 OR 1=1 -- ⇒ lấy tất cả users!
\`\`\`
\`\`\`typescript
// ✅ GOOD: Parameterized query
const userId = req.query.id;
const user = await db.query('SELECT * FROM users WHERE id = ?', [userId]);
\`\`\`
### NoSQL Injection (MongoDB)
\`\`\`typescript
// ❌ BAD
const user = await User.findOne({ email: req.body.email });
// Attacker: { "email": { "$ne": null } } ⇒ bypass authentication!
\`\`\`
\`\`\`typescript
// ✅ GOOD: Validate input type
import { z } from 'zod';
const loginSchema = z.object({
email: z.string().email(),
password: z.string().min(8)
});
const { email, password } = loginSchema.parse(req.body);
const user = await User.findOne({ email });
\`\`\`
## 4. Insecure Design
### Ví dụ: Password reset không an toàn
\`\`\`typescript
// ❌ BAD: Token dự đoán
const resetToken = user.id + Date.now();
\`\`\`
\`\`\`typescript
// ✅ GOOD: Cryptographically secure token
import crypto from 'crypto';
const resetToken = crypto.randomBytes(32).toString('hex');
const hashedToken = crypto.createHash('sha256').update(resetToken).digest('hex');
await db.users.update(userId, {
resetToken: hashedToken,
resetTokenExpiry: new Date(Date.now() + 3600000) // 1 hour
});
\`\`\`
## 5. Security Misconfiguration
### Ví dụ
\`\`\`typescript
// ❌ BAD: CORS cho phép tất cả
app.use(cors({ origin: '*' }));
\`\`\`
\`\`\`typescript
// ✅ GOOD: CORS restricted
const allowedOrigins = [
'https://myapp.com',
'https://admin.myapp.com'
];
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true
}));
\`\`\`
### Security Headers
\`\`\`typescript
import helmet from 'helmet';
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
\`\`\`
## 6. Vulnerable Components
### Kiểm tra dependencies
\`\`\`bash
# npm audit
npm audit --audit-level=high
# Snyk
npx snyk test
# OWASP Dependency Check
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
\`\`\`
### Tự động cập nhật
\`\`\`yaml
# Dependabot config
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
\`\`\`
## 7. Authentication Failures
### Rate Limiting
\`\`\`typescript
import rateLimit from 'express-rate-limit';
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // 5 requests
message: 'Too many login attempts, please try again later'
});
app.post('/api/login', loginLimiter, async (req, res) => {
// login logic
});
\`\`\`
### Multi-Factor Authentication
\`\`\`typescript
import speakeasy from 'speakeasy';
import QRCode from 'qrcode';
// Generate secret
const secret = speakeasy.generateSecret({
name: 'MyApp ([email protected])'
});
// Generate QR code
const qrCode = await QRCode.toDataURL(secret.otpauth_url!);
// Verify token
const verified = speakeasy.totp.verify({
secret: secret.base32,
encoding: 'base32',
token: userToken,
window: 2
});
\`\`\`
## 8. Software and Data Integrity Failures
### Subresource Integrity (SRI)
\`\`\`html
<!-- Load CDN với integrity check -->
<script
src="https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js"
integrity="sha384-xyz..."
crossorigin="anonymous">
</script>
\`\`\`
## 9. Logging and Monitoring Failures
### Structured Logging
\`\`\`typescript
import winston from 'winston';
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
// Log security events
logger.warn('Failed login attempt', {
email: req.body.email,
ip: req.ip,
userAgent: req.get('user-agent')
});
\`\`\`
## 10. Server-Side Request Forgery (SSRF)
\`\`\`typescript
// ❌ BAD: Cho phép fetch bất kỳ URL
app.post('/api/fetch', async (req, res) => {
const response = await fetch(req.body.url);
// Attacker: { url: "http://localhost:8080/admin" }
});
\`\`\`
\`\`\`typescript
// ✅ GOOD: Whitelist domains
const allowedDomains = ['api.example.com', 'cdn.example.com'];
app.post('/api/fetch', async (req, res) => {
const url = new URL(req.body.url);
if (!allowedDomains.includes(url.hostname)) {
return res.status(400).json({ error: 'Invalid domain' });
}
const response = await fetch(url.toString());
res.json(await response.json());
});
\`\`\`
## Checklist tổng hợp
- [ ] Tất cả endpoints có authentication
- [ ] Tất cả sensitive data được encrypt
- [ ] Dùng parameterized queries
- [ ] Validate tất cả user input
- [ ] Security headers (helmet.js)
- [ ] Rate limiting cho login/API
- [ ] Dependencies được audit hàng tuần
- [ ] Logging các security events
- [ ] HTTPS everywhere
- [ ] CSP headers configured
## Kết luận
Bảo mật không phải là feature, mà là foundation. Implement từ đầu, không thể \"thêm sau\".SecurityEngineering
Chia sẻ