[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
---
|
||||
id: security-owasp-top-10-practical
|
||||
title: OWASP Top 10 — 실전 방어 체크리스트
|
||||
category: Coding
|
||||
status: draft
|
||||
source_trust_level: B
|
||||
verification_status: conceptual
|
||||
created_at: 2026-05-09
|
||||
updated_at: 2026-05-09
|
||||
tags: [security, owasp, vibe-coding]
|
||||
tech_stack: { language: "TS / 다양", applicable_to: ["Backend", "Frontend"] }
|
||||
applied_in: []
|
||||
aliases: [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 방어)
|
||||
```ts
|
||||
// ❌
|
||||
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);
|
||||
});
|
||||
```
|
||||
|
||||
```sql
|
||||
-- DB 레벨 추가 방어 (RLS)
|
||||
CREATE POLICY user_isolation ON orders FOR SELECT USING (user_id = current_setting('app.user_id')::UUID);
|
||||
```
|
||||
|
||||
### A02 — 암호화
|
||||
```ts
|
||||
// 비밀번호 = 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
|
||||
```ts
|
||||
// ❌ 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 } });
|
||||
```
|
||||
|
||||
```ts
|
||||
// Command injection
|
||||
exec(`convert ${userInput} out.png`); // ❌
|
||||
execFile('convert', [userInput, 'out.png']); // ✅ shell 안 거침
|
||||
```
|
||||
|
||||
```ts
|
||||
// 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)
|
||||
```ts
|
||||
// 로그인 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
|
||||
```ts
|
||||
// 안 쓰는 endpoint / debug / default password 끄기
|
||||
app.disable('x-powered-by');
|
||||
helmet(); // 보안 헤더 자동
|
||||
// CORS 명시 origin
|
||||
cors({ origin: ['https://app.com'], credentials: true });
|
||||
```
|
||||
|
||||
### A06 — Vulnerable Components
|
||||
```bash
|
||||
npm audit
|
||||
npm audit fix
|
||||
# 또는 Snyk / Dependabot 자동
|
||||
```
|
||||
|
||||
### A07 — Auth
|
||||
```ts
|
||||
// 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
|
||||
```ts
|
||||
// CI 가 lockfile 없이 install 금지
|
||||
// npm ci --ignore-scripts (postinstall 악성 차단)
|
||||
// SBOM 생성
|
||||
// JWT signed + verify with library (직접 X)
|
||||
```
|
||||
|
||||
### A09 — Logging
|
||||
```ts
|
||||
log.warn('login failed', { email, ip, reason }); // 평문 PW 절대 X
|
||||
// 보안 이벤트 SIEM 으로
|
||||
```
|
||||
|
||||
### A10 — SSRF
|
||||
```ts
|
||||
// ❌ 사용자 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 헤더
|
||||
```ts
|
||||
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.
|
||||
|
||||
## 🔗 관련 문서
|
||||
- [[Security_2FA_TOTP_WebAuthn]]
|
||||
- [[Security_OAuth_Flows]]
|
||||
- [[Security_CSP_Headers]]
|
||||
- [[Security_Auth_Authz_Patterns]]
|
||||
Reference in New Issue
Block a user