Přeskočit na obsah

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.

7 kroků · Funguje pro jakýkoliv stack
Proč tohle potřebuješ: Studie z roku 2025 ukázala 69 zranitelností v 15 AI-vygenerovaných aplikacích — 100% chyběly security headers a CSRF ochrana. Další analýza našla 318 zranitelností ve 100 vibe-coded projektech. AI kód funguje — ale fungující neznamená bezpečný.
1. Secrets & klíče

Najdi přihlašovací údaje, které může kdokoliv s přístupem ke kódu nebo frontendu ukrást.

Jak to najít v kódu
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}"
Na co se zaměřit
  • 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
Nebezpečný kód
const OPENAI_API_KEY = "sk-proj-abc123...";
const supabase = createClient(URL, "eyJhbGci...");
Správný přístup
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.

Jak to najít v kódu
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}"
Na co se zaměřit
  • 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
Nebezpečný kód
// 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);
});
Správný přístup
// 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.

Jak to najít v kódu
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*"
Na co se zaměřit
  • 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í)
Nebezpečný kód
# 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()
Správný přístup
# 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.

Jak to najít v kódu
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}"
Na co se zaměřit
  • 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)
Nebezpečný kód
# SQL injection
query = f"SELECT * FROM users WHERE name = '{username}'"

# XSS
element.innerHTML = userInput

# RCE
os.system(f"convert {user_filename} output.jpg")
Správný přístup
# 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.

Jak to najít v kódu
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}"
Na co se zaměřit
  • Žá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
Nebezpečný kód
// Žádná validace — útočník uploadne shell.php
app.post("/upload", upload.single("file"), (req, res) => {
  fs.writeFileSync(`./public/${file.originalname}`, file.buffer);
});
Správný přístup
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.

Jak to najít v kódu
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
Na co se zaměřit
  • 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)
Nebezpečný kód
# 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
Správný přístup
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.

Jak to najít v kódu
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}"
Na co se zaměřit
  • 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)
Nebezpečný kód
// 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);
});
Správný přístup
CORS: pouze konkrétní domény
CSRF tokeny na formulářích
Rate limiting na auth endpointech
Security middleware (helmet / SecurityMiddleware)
HTTPS vynucené
Tip: Zkopíruj jednotlivé kroky do AI nástroje a požádej ho aby zkontroloval tvůj kód. Například: "Projdi můj kód a zkontroluj bod 1 — najdi všechny hardcoded secrets a přesuň je do .env souboru."