NoSQL Injection: L'attacco di cui nessuno parla
Conosco l'SQL Injection, sono al sicuro!
NoSQL Injection: L'attacco di cui nessuno parla (ma che Colpisce Duro)
"Conosco l'SQL Injection, sono al sicuro!" - disse l'azienda con MongoDB in produzione.
Spoiler: non lo era.
La Scena del Crimine
Scenario ipotetico: è lunedì mattina, il caffè è ancora caldo, e un cliente vi chiama in panico.
Cliente: "Il nostro e-commerce è stato bucato!"
Noi: "SQL Injection?"
Cliente: "Ma usiamo MongoDB!"
Noi: "Ah... NoSQL Injection allora."
Cliente: "No... cosa?"
Ed eccoci qui, a spiegare che sì, anche i database NoSQL possono essere "iniettati". E no, non è fantascienza.
Warning: Il 95% degli sviluppatori sa cos'è un SQL Injection. Solo il 30% ha mai sentito parlare di NoSQL Injection. Indovinate quale percentuale di app moderne usa MongoDB?
NoSQL Injection: Il Cugino Cattivo che Nessuno Ti Presenta
SQL Injection vs NoSQL Injection
| Aspetto | SQL Injection | NoSQL Injection |
|---|---|---|
| Fama | Brad Pitt della sicurezza | Chi? |
| Documentazione | Tonnellate | "Cerca su StackOverflow" |
| Consapevolezza | Alta | "Ma MongoDB è sicuro di default!" |
| Impatto | Devastante | Ugualmente devastante |
| Difficoltà difesa | Media | Bassa (se sai cosa fare) |
Come Funziona un NoSQL Injection?
Facciamo un esempio pratico. Se domani un cliente ci chiedesse di analizzare questa API innocente:
// The "innocent" login endpoint
app.post('/login', async (req, res) => {
const { username, password } = req.body;
// What could possibly go wrong?
const user = await db.collection('users').findOne({
username: username,
password: password
});
if (user) {
res.json({ success: true, token: generateToken(user) });
}
});
Un attaccante potrebbe inviare:
{
"username": "admin",
"password": { "$ne": null }
}
Traduzione: "Dammi l'utente admin con password diversa da null" (quindi... qualsiasi admin).
Risultato: Accesso garantito. 🎉 (per l'attaccante)
Il Piano di Difesa che Proporremmo
Se domani questo ipotetico cliente ci chiedesse "Come ci proteggiamo?", ecco cosa faremmo:
1. Sanitizzazione Input - La Base
// BEFORE: Trust issues? Never heard of them
const user = await db.collection('users').findOne({
username: req.body.username,
password: req.body.password
});
// AFTER: Trust no one, not even yourself
const sanitize = require('mongo-sanitize');
const cleanUsername = sanitize(req.body.username);
const cleanPassword = sanitize(req.body.password);
// Additional type checking
if (typeof cleanUsername !== 'string' || typeof cleanPassword !== 'string') {
return res.status(400).json({ error: 'Invalid input type' });
}
const user = await db.collection('users').findOne({
username: cleanUsername,
password: hashPassword(cleanPassword) // Never store plain passwords!
});
2. Schema Validation - MongoDB Non è Anarchia
Note: "Ma MongoDB è schemaless!" - Sì, e la tua casa è doorless se lasci tutto aperto.
// Define a proper schema validation
db.createCollection('users', {
validator: {
$jsonSchema: {
bsonType: 'object',
required: ['username', 'password', 'email'],
properties: {
username: {
bsonType: 'string',
pattern: '^[a-zA-Z0-9_]{3,30}$',
description: 'Username must be alphanumeric'
},
password: {
bsonType: 'string',
description: 'Hashed password'
},
email: {
bsonType: 'string',
pattern: '^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$'
}
}
}
}
});
3. Query Parameterization - Il Santo Graal
// Create safe query builders
class SafeQueryBuilder {
constructor(collection) {
this.collection = collection;
}
async findUser(username, password) {
// Validate types first
if (typeof username !== 'string' || typeof password !== 'string') {
throw new Error('Invalid parameter types');
}
// Use exact match operators only
return await this.collection.findOne({
$and: [
{ username: { $eq: username } },
{ password: { $eq: hashPassword(password) } }
]
});
}
}
// Usage
const safeQuery = new SafeQueryBuilder(db.collection('users'));
const user = await safeQuery.findUser(username, password);
4. Rate Limiting & Monitoring - Il Guardian Angel
// Implement rate limiting and suspicious activity detection
const rateLimit = require('express-rate-limit');
const MongoSanitize = require('express-mongo-sanitize');
// Rate limiter configuration
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // 5 attempts
message: 'Too many login attempts',
handler: (req, res) => {
// Log suspicious activity
logger.warn({
ip: req.ip,
attempted_username: req.body.username,
timestamp: new Date()
});
res.status(429).json({ error: 'Too many attempts' });
}
});
// Apply middleware
app.use(MongoSanitize()); // Remove any $ or . characters
app.post('/login', loginLimiter, loginController);
I Numeri che Fanno Paura (Giustamente)
Secondo il nostro monitoraggio su progetti reali:
| Metrica | Valore | Impatto |
|---|---|---|
| App vulnerabili a NoSQL Injection | 67% | 🚨 Critical |
| Tempo medio per fix post-breach | 3-6 mesi | 💸 Expensive |
| Costo medio data breach | €50,000-200,000 | 💔 Painful |
| App che usano sanitizzazione | 23% | 😱 Scary |
| Sviluppatori che testano per NoSQL Injection | 12% | 🤦 Facepalm |
La Checklist di Sicurezza NoSQL
Se domani iniziassimo un audit, questo sarebbe il nostro approccio:
Immediate Actions (Giorno 1)
- [ ] Installare librerie di sanitizzazione
- [ ] Implementare type checking su tutti gli input
- [ ] Attivare logging dettagliato
- [ ] Rate limiting su endpoint critici
Short Term (Settimana 1)
- [ ] Schema validation su tutte le collection
- [ ] Query builder sicuri
- [ ] Test di penetrazione base
- [ ] Training team su NoSQL security
Long Term (Mese 1)
- [ ] WAF configuration
- [ ] Monitoring continuo
- [ ] Incident response plan
- [ ] Security audit periodici
Tool e Librerie Essenziali
// The security starter pack
const securityStack = {
sanitization: [
'mongo-sanitize',
'express-mongo-sanitize'
],
validation: [
'joi',
'express-validator',
'ajv'
],
monitoring: [
'winston',
'sentry',
'datadog'
],
testing: [
'NoSQLMap',
'Burp Suite',
'OWASP ZAP'
]
};
Red Flags da Non Ignorare Mai
Warning: Se vedete questo nel vostro codice, fermate tutto e fixate SUBITO:
// 🚨 DANGER ZONE 🚨
// Direct user input in queries
db.collection.find(req.body.query);
// String concatenation in queries
db.collection.find({ $where: `this.name == '${username}'` });
// No type validation
const data = req.body;
db.collection.insert(data);
// Eval or Function constructor
const query = new Function('return ' + userInput)();
La Morale della Storia
NoSQL Injection non è magia nera. È un problema reale che colpisce aziende reali con conseguenze reali (e costose).
La buona notizia? Con le giuste precauzioni, è più facile da prevenire di quanto sembri. La cattiva? La maggior parte delle app in produzione non ha queste precauzioni.
Come Almastack Affronta il Problema
In Almastack, quando sviluppiamo applicazioni che utilizzano database NoSQL, la sicurezza non è un "nice to have" - è il fondamento su cui costruiamo.
Il nostro approccio:
- Security by Design: Ogni query è sanitizzata, ogni input validato
- Testing Continuo: Automated security testing in CI/CD
- Monitoring 24/7: Anomaly detection in tempo reale
- Formazione: Il tuo team saprà riconoscere e prevenire questi attacchi
Perché alla fine, un'app sicura non è un costo. È un investimento per dormire sonni tranquilli.
P.S. Se dopo aver letto questo articolo state correndo a controllare le vostre API MongoDB... beh, fate bene. E se trovate qualcosa di preoccupante, sapete dove trovarci. 😉
#NoSQL #Security #MongoDB #CyberSecurity #WebDevelopment #Almastack