Files
2nd/10_Wiki/Topics/Coding/Security_OWASP_Top_10_Practical.md
T
2026-05-09 21:08:02 +09:00

5.5 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
security-owasp-top-10-practical OWASP Top 10 — 실전 방어 체크리스트 Coding draft B conceptual 2026-05-09 2026-05-09
security
owasp
vibe-coding
language applicable_to
TS / 다양
Backend
Frontend
OWASP
A01
broken access control
injection
SSRF
IDOR

OWASP Top 10 (2021) 실전

매년 거의 같은 카테고리. A01 Broken Access Control = 인증 / 권한 검증 누락이 1위. 코드 안 검증 위치 (controller / service / DB) + 자동 테스트.

📖 핵심 개념

  • A01 Broken Access Control
  • A02 Cryptographic Failures
  • A03 Injection (SQLi, NoSQLi, OS, LDAP)
  • A04 Insecure Design
  • A05 Security Misconfiguration
  • A06 Vulnerable Components
  • A07 Identification & Authentication Failures
  • A08 Data Integrity (CI/CD, deserialization)
  • A09 Logging / Monitoring Failures
  • A10 SSRF

💻 코드 패턴

A01 — 권한 검증 (IDOR 방어)

// ❌
app.get('/orders/:id', async (req, res) => {
  const order = await db.orders.find(req.params.id);
  res.json(order); // 다른 사용자 거 보임
});

// ✅
app.get('/orders/:id', authRequired, async (req, res) => {
  const order = await db.orders.find({ id: req.params.id, userId: req.user.id });
  if (!order) return res.status(404).end();
  res.json(order);
});
-- DB 레벨 추가 방어 (RLS)
CREATE POLICY user_isolation ON orders FOR SELECT USING (user_id = current_setting('app.user_id')::UUID);

A02 — 암호화

// 비밀번호 = bcrypt / argon2id (절대 SHA256 만 X)
import argon2 from 'argon2';
const hash = await argon2.hash(password, { type: argon2.argon2id });
const ok = await argon2.verify(hash, candidate);

// 데이터 암호화 = AES-GCM
import { createCipheriv, randomBytes } from 'node:crypto';
const iv = randomBytes(12);
const cipher = createCipheriv('aes-256-gcm', key, iv);
const enc = Buffer.concat([cipher.update(plain), cipher.final()]);
const tag = cipher.getAuthTag();
// 저장: iv + enc + tag

A03 — Injection

// ❌ SQL injection
db.query(`SELECT * FROM users WHERE email = '${email}'`);

// ✅ Parameterized
db.query('SELECT * FROM users WHERE email = $1', [email]);

// ✅ ORM
db.users.find({ where: { email } });
// Command injection
exec(`convert ${userInput} out.png`);   // ❌
execFile('convert', [userInput, 'out.png']); // ✅ shell 안 거침
// NoSQL injection
db.users.find({ email: req.body.email }); // body 가 { $ne: null } 이면 모두 반환
// → 명시적 검증
db.users.find({ email: String(req.body.email) });

A04 — Insecure Design (rate limiting, lockout)

// 로그인 5회 실패 → 15분 lockout
const attempts = await redis.incr(`login:${email}`);
await redis.expire(`login:${email}`, 900);
if (attempts > 5) throw new Error('Account locked');

A05 — Misconfiguration

// 안 쓰는 endpoint / debug / default password 끄기
app.disable('x-powered-by');
helmet(); // 보안 헤더 자동
// CORS 명시 origin
cors({ origin: ['https://app.com'], credentials: true });

A06 — Vulnerable Components

npm audit
npm audit fix
# 또는 Snyk / Dependabot 자동

A07 — Auth

// MFA 활성
// Strong password rules: NIST 2025 = 길이만 (8+) — 복잡도 X
// JWT exp 짧게 + refresh
// HttpOnly + Secure + SameSite=Strict cookie
res.cookie('session', token, {
  httpOnly: true, secure: true, sameSite: 'strict', maxAge: 3600_000,
});

A08 — Integrity

// CI 가 lockfile 없이 install 금지
// npm ci --ignore-scripts (postinstall 악성 차단)
// SBOM 생성
// JWT signed + verify with library (직접 X)

A09 — Logging

log.warn('login failed', { email, ip, reason }); // 평문 PW 절대 X
// 보안 이벤트 SIEM 으로

A10 — SSRF

// ❌ 사용자 URL 그대로 fetch
fetch(req.body.url);

// ✅ allowlist + private IP 차단
const allowed = ['api.partner.com'];
const u = new URL(req.body.url);
if (!allowed.includes(u.host)) throw new Error('not allowed');
const ip = await dns.resolve(u.host);
if (isPrivateIP(ip)) throw new Error('private ip');

CSP 헤더

helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", 'https://cdn.example.com'],
      imgSrc: ["'self'", 'data:', 'https:'],
      connectSrc: ["'self'", 'https://api.example.com'],
    },
  },
});

🤔 의사결정 기준

위험 우선순위 도구
Public API A01, A03, A07, A10
사용자 데이터 A02, A09
OSS 의존 A06 (Snyk, Dependabot)
Admin 패널 A01, A04
결제 A02, PCI
Webhook HMAC + replay 방어

안티패턴

  • 인증 = 권한이라고 착각: 로그인 했다고 모든 거 접근 X.
  • Frontend 만 검증: bypass 가능.
  • 에러 메시지 상세 (stack): 정보 노출.
  • SHA256 / MD5 password: rainbow table.
  • JWT secret 공유 / 하드코딩: leak.
  • CORS *** + credentials: 자동 spec 거부지만 잡힘.
  • Unsigned URL upload: 사용자가 임의 path.
  • <input type="password"> 만 = 안전 가정: HTTPS + 정책 같이.

🤖 LLM 활용 힌트

  • A01-A03 자동 검증 (lint + 테스트).
  • helmet + CORS + rate-limit + zod 4종 어디나.
  • 매 API 에 (1) 인증 (2) 권한 (3) 입력 검증 (4) 출력 sanitize.

🔗 관련 문서