OWASP Top 10 2025 — AI 시대 웹 취약점 10선
권한 깨짐 · 암호 실패 · 인젝션 · 부실 설계 · SSRF · 의존성 — 가장 자주 터지는 10가지.
AI가 만든 코드에 이 10가지 패턴이 들어있으면 프로덕션 배포 직후 털린다. 각 항목을 '내 코드에서 어디서 발생 가능한가'로 치환해 읽는다.
OWASP Top 10은 전 세계 웹 보안 단골 취약점 랭킹. 버전마다 순위가 바뀌지만 본질은 같다. 아래는 2021 공식 + 2025 추세를 통합한 바이브코더 관점 정리.
| # | 취약점 | 근본 원인 | 바이브코더가 할 일 |
|---|---|---|---|
| A01 | Broken Access Control (IDOR 등) | 인가 누락 | 서버/DB에서 소유권·역할 체크 (ch24-1) |
| A02 | Cryptographic Failures | 약한 암호, 평문 저장 | TLS 1.2+, bcrypt/argon2, AES-GCM |
| A03 | Injection (SQL·NoSQL·Cmd) | 사용자 입력을 쿼리/명령에 직접 삽입 | Prepared Statement, ORM, 입력 검증 |
| A04 | Insecure Design | 설계 단계 결함 | 위협 모델링, 테스트 부정 케이스 |
| A05 | Security Misconfiguration | 기본 비번, 노출 에러, 열린 포트 | CSP 헤더, 최소 권한, Error 핸들링 |
| A06 | Vulnerable Components | 오래된 라이브러리 | `npm audit`, Dependabot |
| A07 | Auth Failures | 약한 비번, 무제한 시도 | MFA, Rate Limit, bcrypt |
| A08 | Software/Data Integrity | 서명 없는 업데이트, CI 공격 | SBOM, 서명 검증 |
| A09 | Logging/Monitoring Failures | 침입 모름 | 구조화 로그, 알림 (ch09-5 관측성) |
| A10 | SSRF | 서버가 내부 URL 요청하게 유도 | URL 화이트리스트, 메타데이터 차단 |
2025년대 추가 테마: LLM 보안. OWASP LLM Top 10 별도 발간. 프롬프트 인젝션 (악성 입력이 시스템 프롬프트 오염), 민감 정보 유출 (LLM에 비밀 데이터 전달), 모델 공급망 공격. Claude Code 쓰는 바이브코더에게 실제로 직결.
// ━━━ A01 방어: 소유권 체크 ━━━
app.get("/api/posts/:id/edit", async (req, res) => {
const post = await db.posts.find(req.params.id);
if (!post) return res.sendStatus(404);
if (post.authorId !== req.user.id) return res.sendStatus(403); // ← 인가
// 편집 로직
});
// ━━━ A03 방어: Prepared Statement / ORM ━━━
// ❌ SQL Injection
const user = await db.query(`SELECT * FROM users WHERE email='${email}'`);
// email = "' OR 1=1--" → 전체 유저 노출
// ✅ 매개변수 바인딩
const user = await db.query("SELECT * FROM users WHERE email = $1", [email]);
// ━━━ A03 방어: Shell 명령 인젝션 ━━━
// ❌ exec("convert " + filename + " out.png") → 공백·; 들어오면 임의 명령
// ✅ execFile("convert", [filename, "out.png"]) → 인자 배열로
// ━━━ A05 방어: CSP 헤더 (XSS 2차 방어선) ━━━
app.use((req, res, next) => {
res.setHeader("Content-Security-Policy",
"default-src 'self'; script-src 'self'; object-src 'none'");
res.setHeader("X-Content-Type-Options", "nosniff");
res.setHeader("X-Frame-Options", "DENY");
res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
next();
});
// ━━━ A07 방어: 로그인 Rate Limit ━━━
import rateLimit from "express-rate-limit";
app.use("/api/login", rateLimit({
windowMs: 15 * 60_000, // 15분
max: 5, // IP당 5회
message: "Too many attempts",
}));
// ━━━ A10 방어: SSRF ━━━
// 사용자가 입력한 URL을 서버가 fetch할 때
const allowed = ["https://images.jit.co.kr", "https://cdn.jit.co.kr"];
const parsed = new URL(userUrl);
if (!allowed.includes(parsed.origin)) throw new Error("blocked");
// 추가: AWS 메타데이터(169.254.169.254) 차단, 사설 IP 차단Claude에게 "이 코드에 OWASP Top 10 관점 취약점 있어?" 물어보면 꽤 잘 찾는다. 정기적으로 코드 리뷰 시 습관화.
의존성 감사 루틴. 주 1회: `npm audit` → High/Critical 즉시 업데이트. GitHub Dependabot 활성화. 중요 프로젝트는 SBOM(Software Bill of Materials) 생성 — `npm ls --all` 또는 `syft`.
실전 최소 보안 체크리스트 10. ① TLS 1.2+ / HSTS ② HttpOnly+Secure+SameSite 쿠키 ③ bcrypt/argon2 ④ Prepared Statement 또는 ORM ⑤ 서버측 인가 체크 ⑥ CSP·XFO·XCTO 헤더 ⑦ Rate Limit (로그인·API) ⑧ `.env` Git 제외 ⑨ 로그·알림 ⑩ `npm audit` 주간.
사용자가 입력한 URL을 서버가 fetch하게 유도해 내부 시스템을 탐색하는 공격 이름은?
SQL Injection을 근본적으로 막는 표준 기법은?
`npm audit`을 한 번만 돌리면 보안 의존성 관리가 끝난다.