Security Review
Praktický průvodce jak projít bezpečnost svého projektu. Zaměřeno na vibe-coded aplikace — typické chyby, které AI generuje, a kde je hledat.
1. Secrets & klíče
Najdi přihlašovací údaje, které může kdokoliv s přístupem ke kódu nebo frontendu ukrást.
grep -r "api_key\|API_KEY\|secret\|SECRET\|password\|PASSWORD\|token\|TOKEN" --include="*.{js,ts,py,env*,yml,yaml,json}"
grep -r "sk-proj-\|sk_live_\|AKIA\|ghp_\|sb_secret_" --include="*.{js,ts,py,jsx,tsx}"
- • Hardcoded API klíče (Stripe, OpenAI, AWS, Supabase) v kódu
- • Databázové credentials přímo v source code
- • JWT secrets, session klíče, encryption klíče
- • Secrets ve frontend kódu nebo bundlech (viditelné v prohlížeči)
- • Credentials v komentářích (// TODO: remove test key)
- • Testovací credentials, které fungují v produkci
const OPENAI_API_KEY = "sk-proj-abc123..."; const supabase = createClient(URL, "eyJhbGci...");
Secrets v .env souboru (v .gitignore) Přístup přes process.env / os.getenv() .env.example s placeholder hodnotami
2. Autentizace & autorizace
Najdi cesty, jak se přihlásit jako někdo jiný nebo eskalovat na admina.
grep -r "login\|signup\|authenticate\|session\|jwt\|oauth" --include="*.{js,ts,py,rb,php}"
grep -r "is_admin\|isAdmin\|role\|permission\|authorize" --include="*.{js,ts,py,rb,php}"
grep -r "cookie\|session\|localStorage" --include="*.{js,ts,py}"
- • User ID z URL parametrů místo ze session (IDOR)
- • Role/admin status z request body bez serverové validace
- • Autorizace pouze na frontendu (API stále přístupné)
- • JWT bez expirace nebo bez ověření podpisu
- • Session cookies bez HttpOnly, Secure, SameSite
- • Admin routy bez serverové kontroly role
- • Password reset s predikovatelnými tokeny
// User ID z URL — útočník ho změní!
app.get("/api/profile", (req, res) => {
const userId = req.query.userId;
return db.getProfile(userId);
});
// User ID vždy ze session
app.get("/api/profile", (req, res) => {
const userId = req.session.userId;
return db.getProfile(userId);
});
3. Přístup k cizím datům
Najdi endpointy kde změna ID v URL vrátí data jiného uživatele.
grep -r "GET.*user\|profile\|account\|order\|payment" --include="*.{js,ts,py,rb,php}"
grep -r "WHERE.*user\|filter.*user\|findOne\|findById" --include="*.{js,ts,py,rb,php}"
find . -name "*resolvers*" -o -name "*schema*"
- • API routy přijímající record ID bez kontroly vlastnictví
- • ORM dotazy filtrující jen podle ID, ne podle přihlášeného uživatele
- • List endpointy bez filtrování na aktuálního uživatele
- • GraphQL resolvery bez ownership kontroly
- • Veřejné endpointy vracející citlivá data (PII, finance, zdraví)
# Vrací JAKOUKOLIV objednávku, ne jen uživatelovu!
@app.get("/api/orders/{order_id}")
def get_order(order_id):
return db.query(Order).filter(Order.id == order_id).first()
# Ověří vlastnictví záznamu
@app.get("/api/orders/{order_id}")
def get_order(order_id, user=Depends(get_current_user)):
return db.query(Order).filter(
Order.id == order_id,
Order.user_id == user.id
).first()
4. Injection & spuštění kódu
Najdi SQL injection, XSS, prompt injection a RCE zranitelnosti.
grep -r "SELECT.*+\|query.*%.*s\|execute.*format\|raw.*sql" --include="*.{js,ts,py,rb,php}"
grep -r "innerHTML\|dangerouslySetInnerHTML\|html.*safe\|raw.*html" --include="*.{js,ts,jsx,tsx,py,rb}"
grep -r "eval\|exec\|system\|popen\|subprocess\|spawn" --include="*.{js,ts,py,rb,php}"
grep -r "openai\|anthropic\|completion\|prompt\|llm" --include="*.{js,ts,py}"
- • String concatenation v SQL dotazech (f-stringy, template literals)
- • .raw() nebo .execute() s user inputem
- • innerHTML, dangerouslySetInnerHTML s uživatelskými daty
- • Template filtry |safe nebo |raw na user obsahu
- • eval(), exec(), Function() s uživatelským vstupem
- • subprocess/shell commands s user inputem
- • Uživatelský vstup v system promptech LLM (prompt injection)
- • Unsafe deserializace (pickle, unserialize, yaml.load)
# SQL injection
query = f"SELECT * FROM users WHERE name = '{username}'"
# XSS
element.innerHTML = userInput
# RCE
os.system(f"convert {user_filename} output.jpg")
# Parametrizované dotazy
db.execute("SELECT * FROM users WHERE name = %s", (username,))
# Bezpečný text
element.textContent = userInput
# Bez shell injection
subprocess.run(['convert', user_filename, 'output.jpg'])
5. Upload souborů
Najdi možnosti uploadu vedoucí ke spuštění kódu nebo XSS.
grep -r "upload\|multer\|formidable\|FileStorage\|multipart" --include="*.{js,ts,py,rb,php}"
grep -r "ImageMagick\|PIL\|sharp\|ffmpeg" --include="*.{js,ts,py}"
grep -r "s3\|blob\|storage\|bucket" --include="*.{js,ts,py,rb,php}"
- • Žádná validace typu souboru (přijímá .php, .exe, .sh)
- • Validace pouze na frontendu (obejitelná)
- • Soubory uložené v executable adresáři
- • Originální názvy souborů (directory traversal: ../../../etc/passwd)
- • Žádné limity velikosti (DoS přes obrovské soubory)
- • Chybí ověření obsahu (magic bytes) — spoléhání jen na příponu
// Žádná validace — útočník uploadne shell.php
app.post("/upload", upload.single("file"), (req, res) => {
fs.writeFileSync(`./public/${file.originalname}`, file.buffer);
});
Allowlist přípon: ['.jpg', '.png', '.pdf'] Ověření obsahu přes magic bytes Přejmenování na UUID Uložení mimo web root nebo cloud storage Limity velikosti
6. Test vs. produkce
Najdi testovací backdoory a debug funkce ponechané v produkci.
grep -r "NODE_ENV\|DEBUG\|ENVIRONMENT" --include="*.{js,ts,py,env*,yml}"
grep -r "test.*user\|admin.*test\|debug\|FIXME\|TODO.*production" --include="*.{js,ts,py,rb,php}"
ls -la *.env* config/*.yml docker-compose*.yml
- • Testovací účty fungující v produkci (admin@test.com / test123)
- • Debug mode zapnutý (stack traces, SQL dotazy viditelné)
- • Debug routy nebo flagy aktivní v produkci
- • Verbose error messages prozrazující internals
- • Mock authentication bypass stále aktivní
- • Logování citlivých dat (hesla, tokeny, PII)
# Backdoor účet fungující v produkci!
if username == "admin@test.com" and password == "test123":
return create_admin_session()
# Debug mode vždy zapnutý
DEBUG = True
DEBUG řízený env proměnnou (False v produkci) Vlastní error stránky bez stack traces Žádné testovací credentials v kódu Separátní DB pro test a produkci
7. Základní hygiena
Zkontroluj security headers, CORS, rate limiting a HTTPS.
grep -r "cors\|CORS\|helmet\|security.*header" --include="*.{js,ts,py,rb,php}"
grep -r "rate.*limit\|throttle\|ratelimit" --include="*.{js,ts,py,rb,php}"
grep -r "https\|ssl\|tls\|cert" --include="*.{js,ts,py,yml,yaml}"
- • CORS: Access-Control-Allow-Origin: * s credentials
- • Chybí CSRF ochrana na state-changing operacích
- • Login endpoint bez rate limitingu (brute force)
- • HTTP místo HTTPS v produkci
- • Chybí security headers (CSP, X-Frame-Options, HSTS)
- • Chybí security middleware (helmet, SecurityMiddleware)
// Wide-open CORS
app.use(cors({ origin: "*", credentials: true }));
// Login bez rate limitingu
app.post("/login", (req, res) => {
checkPassword(req.body.username, req.body.password);
});
CORS: pouze konkrétní domény CSRF tokeny na formulářích Rate limiting na auth endpointech Security middleware (helmet / SecurityMiddleware) HTTPS vynucené