07. OWASP Top 10 (2021)

07. OWASP Top 10 (2021)

읎전: 06. 읞가와 ì ‘ê·Œ 제얎 | 닀음: 08. 읞젝션 공격곌 ë°©ì–Ž


OWASP (Open Worldwide Application Security Project) Top 10은 웹 애플늬쌀읎션 볎안 위험에 대핮 가장 널늬 읞정받는 묞서입니닀. 싀제 췚앜점 데읎터륌 Ʞ반윌로 죌Ʞ적윌로 업데읎튞되며, 개발자와 볎안 전묞가륌 위한 표쀀 읞식 묞서 역할을 합니닀. 2021년 판은 위협 환겜의 쀑대한 변화륌 반영하여 섞 가지 새로욎 칎테고늬와 죌요 재펞성읎 있습니닀. 읎 레슚에서는 섀명, 싀제 사례, 췚앜한 윔드, 수정된 윔드, ë°©ì–Ž 전략곌 핚께 ì—Ž 가지 칎테고늬 각각을 닀룹니닀.

학습 목표

  • OWASP Top 10 (2021) 몚든 칎테고늬 읎핎하Ʞ
  • 각 칎테고늬의 췚앜한 윔드 팹턮 식별하Ʞ
  • 각 췚앜점 큎래슀륌 방지하는 안전한 윔드 작성하Ʞ
  • 개발 및 윔드 늬뷰 시 볎안 첎크늬슀튞로 OWASP Top 10 적용하Ʞ
  • 각 췚앜점의 싀제 영향 읞식하Ʞ

1. 개요: 2021 Top 10

┌─────────────────────────────────────────────────────────────────┐
│                  OWASP Top 10 - 2021                             │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  #   칎테고늬                              2017년 대비 변화     │
│  ─── ──────────────────────────────────── ────────────────────  │
│  A01  췚앜한 ì ‘ê·Œ 제얎                      ↑ #5에서 상승        │
│  A02  암혞화 싀팚                           ↑ #3에서 상승(읎늄변겜)│
│  A03  읞젝션                                ↓ #1에서 하띜        │
│  A04  안전하지 않은 섀계                    ★ 신규               │
│  A05  볎안 구성 였류                        ↑ #6에서 상승        │
│  A06  췚앜하고 였래된 구성 요소             ↑ #9에서 상승(읎늄변겜)│
│  A07  식별 및 읞슝 싀팚                     ↓ #2에서 하띜(읎늄변겜)│
│  A08  소프튞웚얎 및 데읎터 묎결성 싀팚      ★ 신규               │
│  A09  볎안 로깅 및 몚니터링 싀팚            ↑ #10에서 상승(읎늄변겜)│
│  A10  서버 ìž¡ 요청 위조 (SSRF)              ★ 신규               │
│                                                                  │
│  죌요 튾렌드:                                                    │
│  - 췚앜한 ì ‘ê·Œ 제얎가 1위 (테슀튞된 앱의 94%)                   │
│  - 읞젝션읎 #1에서 #3윌로 하띜 (프레임워크가 도움)             │
│  - 섞 가지 새 칎테고늬가 현대 위협 반영                         │
│  - 공꞉망 및 묎결성 ìš°ë € 슝가                                   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

2. A01: 췚앜한 ì ‘ê·Œ 제얎

2.1 섀명

ì ‘ê·Œ 제얎는 사용자가 의도된 권한을 벗얎나 행동할 수 없도록 정책을 강제합니닀. 췚앜한 ì ‘ê·Œ 제얎는 가장 음반적읞 웹 애플늬쌀읎션 췚앜점윌로, 테슀튞된 애플늬쌀읎션의 94%에서 발견됩니닀.

┌─────────────────────────────────────────────────────────────────┐
│              A01: 췚앜한 ì ‘ê·Œ 제얎                                │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  음반적읞 앜점:                                                  │
│  - URL/파띌믞터/API 수정윌로 ì ‘ê·Œ 제얎 우회                     │
│  - 닀륞 사람의 계정 볎Ʞ 또는 펞집 (IDOR)                       │
│  - ì ‘ê·Œ 제얎가 누띜된 API ì ‘ê·Œ (POST/PUT/DELETE)                │
│  - 권한 상승 (로귞읞 없읎 ꎀ늬자로 행동)                        │
│  - 메타데읎터 조작 (JWT 재생, ì¿ í‚€ 변조)                        │
│  - 묎닚 API 접귌을 허용하는 CORS 구성 였류                      │
│  - 읞슝되지 않은/ꎀ늬자 페읎지로 강제 람띌우징                  │
│                                                                  │
│  영향: 데읎터 도난, 묎닚 데읎터 수정,                            │
│        계정 탈췚, 전첎 시슀템 칚핎                               │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

2.2 췚앜한 윔드

# 췚앜: ꎀ늬자 엔드포읞튞에 ì ‘ê·Œ 제얎 없음
@app.route('/admin/users/<int:user_id>/delete', methods=['POST'])
def delete_user(user_id):
    # 읎 URL을 아는 사람은 누구나 사용자륌 삭제할 수 있음!
    db.delete_user(user_id)
    return jsonify({"status": "deleted"})


# 췚앜: IDOR - 소유권 확읞 없음
@app.route('/api/orders/<int:order_id>')
@require_auth
def get_order(order_id):
    order = db.get_order(order_id)
    return jsonify(order)  # 사용자 A가 사용자 B의 죌묞을 볌 수 있음

2.3 수정된 윔드

# 수정: 적절한 읞가 확읞
@app.route('/admin/users/<int:user_id>/delete', methods=['POST'])
@require_role('admin')  # ꎀ늬자만 ì ‘ê·Œ 가능
def delete_user(user_id):
    db.delete_user(user_id)
    return jsonify({"status": "deleted"})


# 수정: 소유권 검슝
@app.route('/api/orders/<int:order_id>')
@require_auth
def get_order(order_id):
    order = db.get_order(order_id)
    if not order:
        return jsonify({"error": "Not found"}), 404

    # 죌묞읎 읞슝된 사용자에게 속하는지 검슝
    if order['user_id'] != g.current_user['id']:
        return jsonify({"error": "Not found"}), 404  # 403읎 아닌 404

    return jsonify(order)

2.4 ë°©ì–Ž

  • 공개 늬소슀륌 제왞하고 Ʞ볞적윌로 거부
  • ì ‘ê·Œ 제얎 메컀니슘을 한 번 구현하고 몚든 곳에서 재사용
  • 레윔드 소유권 강제 (사용자가 제공한 ID에만 의졎하지 않Ʞ)
  • 웹 서버 디렉토늬 목록 비활성화
  • ì ‘ê·Œ 제얎 싀팚륌 로귞에 Ʞ록하고 ꎀ늬자에게 알늌
  • 자동화된 슀캔 플핎륌 최소화하Ʞ 위핎 API ì ‘ê·Œ 속도 제한
  • 로귞아웃 시 JWT 토큰 묎횚화 (서버 ìž¡ 토큰 찚닚 목록)

3. A02: 암혞화 싀팚

3.1 섀명

읎전에는 "믌감한 데읎터 ë…žì¶œ"읎띌고 불렞윌며, 읎 칎테고늬는 믌감한 데읎터 녞출로 읎얎지는 암혞화 ꎀ렚 싀팚에 쎈점을 맞춥니닀. 볎혞핎알 할 데읎터륌 암혞화하지 않는 것곌 앜하거나 였래된 암혞화 알고늬슘 사용을 몚두 포핚합니닀.

┌─────────────────────────────────────────────────────────────────┐
│              A02: 암혞화 싀팚                                     │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  슀슀로에게 묌얎볎섞요:                                          │
│  1. ì–Žë–€ 데읎터가 평묞윌로 전송되거나 저장되는가?               │
│  2. 였래되거나 앜한 암혞화 알고늬슘읎나 프로토윜읎 사용되는가? │
│  3. Ʞ볞 암혞화 킀가 사용되거나 킀가 순환되지 않는가?          │
│  4. 암혞화가 강제되지 않는가 (HTTPS 늬디렉션 누띜)?            │
│  5. 적절한 HTTP 볎안 헀더가 누띜되얎 있는가?                   │
│  6. 서버 읞슝서가 올바륎게 검슝되는가?                          │
│  7. 비밀번혞에 대핮 deprecated 핎싱읎 사용되는가 (MD5, SHA1)?  │
│                                                                  │
│  믌감한 데읎터 칎테고늬:                                         │
│  - 비밀번혞, 신용칎드 번혞, 걎강 Ʞ록                           │
│  - 개읞 데읎터, 비슈니슀 비밀                                   │
│  - 개읞정볎 볎혞 규정에 의핎 볎혞되는 데읎터 (GDPR, HIPAA, PCI)│
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

3.2 췚앜한 윔드

# 췚앜: MD5로 비밀번혞 저장
import hashlib

def store_password(password):
    # MD5는 비밀번혞 핎싱에 깚졌음!
    hash_value = hashlib.md5(password.encode()).hexdigest()
    db.store(hash_value)

# 췚앜: 하드윔딩된 암혞화 í‚€
ENCRYPTION_KEY = "my-secret-key-123"  # 소슀 제얎에 컀밋됚!

# 췚앜: ECB 몚드 사용 (팹턮 드러낚)
from Crypto.Cipher import AES
cipher = AES.new(key, AES.MODE_ECB)  # ECB 몚드는 안전하지 않음!
encrypted = cipher.encrypt(data)

# 췚앜: 믌감한 데읎터에 HTTP 사용
# HTTP에서 HTTPS로의 늬디렉션 없음
# HSTS 헀더 없음

3.3 수정된 윔드

# 수정: 비밀번혞에 Argon2 사용
from argon2 import PasswordHasher
ph = PasswordHasher()

def store_password(password):
    hash_value = ph.hash(password)  # 자동 솔팅을 사용한 Argon2id
    db.store(hash_value)

# 수정: 환겜에서 í‚€ 가젞였Ʞ, 소슀 윔드에서 가젞였지 않Ʞ
import os
ENCRYPTION_KEY = os.environ['ENCRYPTION_KEY']  # 256비튞 í‚€

# 수정: GCM 몚드 사용 (읞슝된 암혞화)
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)
nonce = os.urandom(12)  # nonce륌 절대 재사용하지 마섞요
encrypted = aesgcm.encrypt(nonce, data, associated_data)

# 수정: HTTPS 강제 및 볎안 헀더 추가
@app.after_request
def set_security_headers(response):
    response.headers['Strict-Transport-Security'] = \
        'max-age=31536000; includeSubDomains'
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    return response

3.4 ë°©ì–Ž

  • 믌감도에 따띌 데읎터 분류; 분류별로 제얎 적용
  • 불필요한 믌감한 데읎터륌 저장하지 마섞요; 가능한 한 빚늬 폐Ʞ
  • 몚든 믌감한 데읎터륌 저장 시 및 전송 시 암혞화 (TLS 1.2+)
  • 강력하고 표쀀 알고늬슘 사용 (AES-256-GCM, RSA-2048+, Ed25519)
  • 읞슝된 암혞화 사용 (GCM, ChaCha20-Poly1305), ECB는 절대 사용 안 핹
  • Argon2id, bcrypt 또는 scrypt륌 사용하여 비밀번혞 저장
  • 암혞학적윌로 안전한 난수 생성Ʞ륌 사용하여 í‚€ 생성
  • 믌감한 데읎터가 포핚된 페읎지의 캐싱 비활성화

4. A03: 읞젝션

4.1 섀명

읞젝션 결핚은 신뢰할 수 없는 데읎터가 명령 또는 쿌늬의 음부로 읞터프늬터에 전송될 때 발생합니닀. 공격자의 악의적읞 데읎터는 읞터프늬터륌 속여 의도하지 않은 명령을 싀행하거나 권한 없읎 데읎터에 접귌하게 할 수 있습니닀. SQL 읞젝션, NoSQL 읞젝션, OS 명령 읞젝션, LDAP 읞젝션은 몚두 읎 췚앜점의 형태입니닀.

ì°žê³ : 읞젝션은 레슚 08에서 훚씬 더 자섞히 닀룹니닀. 읎 섹션은 요앜을 제공합니닀.

┌─────────────────────────────────────────────────────────────────┐
│              A03: 읞젝션                                          │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  읞젝션 유형:                                                    │
│  ├── SQL 읞젝션           (가장 음반적)                          │
│  ├── NoSQL 읞젝션         (MongoDB 등)                           │
│  ├── 명령 읞젝션          (os.system, subprocess)                │
│  ├── LDAP 읞젝션          (디렉토늬 서비슀)                      │
│  ├── XPath 읞젝션         (XML 쿌늬)                             │
│  ├── 템플늿 읞젝션        (Jinja2, Twig SSTI)                   │
│  └── 표현 ì–žì–Ž            (Spring EL, OGNL)                      │
│                                                                  │
│  귌볞 원읞:                                                      │
│  사용자 입력읎 맀개변수화되거나 적절히 읎슀쌀읎프되는 대신       │
│  쿌늬/명령에 연결됚                                              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

4.2 췚앜 윔드 vs 수정된 윔드

# 췚앜: SQL 읞젝션
@app.route('/search')
def search():
    q = request.args.get('q')
    # 묞자엎 연결 = SQL 읞젝션!
    results = db.execute(f"SELECT * FROM products WHERE name LIKE '%{q}%'")
    return jsonify(results)

# 공격: /search?q=' OR '1'='1' --


# 수정: 맀개변수화된 쿌늬
@app.route('/search')
def search():
    query = request.args.get('q', '')
    results = db.execute(
        "SELECT * FROM products WHERE name LIKE :query",
        {"query": f"%{query}%"}  # 파띌믞터 바읞딩
    )
    return jsonify(results)

4.3 ë°©ì–Ž

  • 맀개변수화된 쿌늬 / 쀀비된 묞 사용 (항상)
  • 맀개변수화륌 처늬하는 ORM 프레임워크 사용 (SQLAlchemy, Django ORM)
  • 몚든 입력 검슝 및 정제 (화읎튞늬슀튞 검슝)
  • 특정 읞터프늬터에 대한 특수 묞자 읎슀쌀읎프
  • 읞젝션 시 대량 공개륌 방지하Ʞ 위핎 쿌늬에 LIMIT 사용

5. A04: 안전하지 않은 섀계

5.1 섀명

읎것은 2021년의 새로욎 칎테고늬로 섀계 및 아킀텍처 결핚곌 ꎀ렚된 위험에 쎈점을 맞춥니닀. 위협 몚덞링, 볎안 섀계 팹턮 및 ì°žì¡° 아킀텍처의 더 많은 사용을 요구합니닀. 안전하지 않은 섀계는 완벜한 구현윌로도 수정할 수 없습니닀 - 결핚읎 있는 섀계는 볞질적윌로 췚앜합니닀.

┌─────────────────────────────────────────────────────────────────┐
│              A04: 안전하지 않은 섀계                              │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  안전하지 않은 섀계 ≠ 안전하지 않은 구현                        │
│                                                                  │
│  ┌──────────────────┐    ┌──────────────────┐                   │
│  │ 안전하지 않은    │    │ 안전하지 않은    │                   │
│  │ 섀계             │    │ 구현             │                   │
│  │                  │    │                  │                    │
│  │ 청사진읎 결핚읎  │    │ 청사진은 좋지만  │                    │
│  │ 있음. 윔드 수정  │    │ 윔드에 버귞가    │                    │
│  │ 윌로 도움 안됚.  │    │ 있음.            │                    │
│  │                  │    │                  │                    │
│  │ 예시:            │    │ 예시:            │                    │
│  │ 비밀번혞 재섀정  │    │ 로귞읞 폌의      │                    │
│  │ 읎메음로 평묞    │    │ SQL 읞젝션       │                    │
│  │ 비밀번혞 전송    │    │                  │                    │
│  │ (섀계상)         │    │                  │                    │
│  └──────────────────┘    └──────────────────┘                   │
│                                                                  │
│  안전하지 않은 섀계의 예:                                        │
│  - 읞슝에 속도 제한 없음 (묎찚별 대입 공격 가능)                │
│  - 비밀번혞 복구의 유음한 방법윌로 볎안 질묞 사용               │
│  - 입력 검슝 아킀텍처 없음 (각 개발자가 자신의 방식윌로 구현)  │
│  - 섀계상 소슀 윔드에 비밀 저장                                 │
│  - 닀쀑 테넌튾 시슀템에서 테넌튾 데읎터 간 분늬 없음            │
│  - 요구사항에서 낚용 사례 누띜 (행복한 겜로만)                  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

5.2 싀제 사례: 영화ꎀ 예앜

# 안전하지 않은 섀계: 속도 제한 없는 영화 티쌓 예앜
# 섀계상 뎇읎 읞Ʞ 영화의 몚든 티쌓을 예앜할 수 있음

@app.route('/api/book', methods=['POST'])
@require_auth
def book_ticket():
    movie_id = request.json['movie_id']
    seats = request.json['seats']  # 좌석 수 제한 없음!

    # 사용자당 속도 제한 없음
    # 거래당 최대 좌석 수 없음
    # 수요가 많은 읎벀튞에 CAPTCHA 없음
    # 사Ʞ 탐지 없음

    booking = create_booking(g.user.id, movie_id, seats)
    return jsonify(booking)


# 안전한 섀계: 적절한 볎혞 장치 포핚

@app.route('/api/book', methods=['POST'])
@require_auth
@rate_limit(max_requests=5, per_minutes=1)  # 속도 제한
def book_ticket():
    movie_id = request.json['movie_id']
    seats = request.json['seats']

    # 섀계 수쀀 제얎
    MAX_SEATS_PER_BOOKING = 6
    if len(seats) > MAX_SEATS_PER_BOOKING:
        return jsonify({"error": f"예앜당 최대 {MAX_SEATS_PER_BOOKING}석"}), 400

    # 사용자가 읎 상영회에 너묎 많은 좌석을 읎믞 예앜했는지 확읞
    existing = get_user_bookings(g.user.id, movie_id)
    if len(existing) >= 2:  # 영화당 사용자당 최대 2개 예앜
        return jsonify({"error": "읎 영화에 대한 최대 예앜 수에 도달했습니닀"}), 400

    # 수요가 많은 읎벀튞의 겜우 추가 검슝 필요
    movie = get_movie(movie_id)
    if movie.get('high_demand'):
        if not verify_captcha(request.json.get('captcha_token')):
            return jsonify({"error": "CAPTCHA 검슝 필요"}), 400

    booking = create_booking(g.user.id, movie_id, seats)
    return jsonify(booking)

5.3 ë°©ì–Ž

  • 쀑요한 읞슝, ì ‘ê·Œ 제얎 및 비슈니슀 로직에 위협 몚덞링 사용
  • 사용자 슀토늬에 볎안 ì–žì–Ž 및 제얎 통합
  • 몚든 쀑요한 흐늄읎 낚용에 저항하는지 검슝하는 닚위 및 통합 테슀튞 작성
  • 싀팚륌 위한 섀계: 사용자/섞션당 늬소슀 소비 제한
  • 신뢰 겜계륌 분늬하Ʞ 위핎 애플늬쌀읎션 레읎얎 계잵화
  • 볎안 섀계 팹턮 사용 (예: 묎상태 섞션 ꎀ늬, 입력 검슝 프레임워크)

6. A05: 볎안 구성 였류

6.1 섀명

볎안 구성 였류는 싀제로 가장 흔히 볌 수 있는 묞제입니닀. 잘못 구성된 권한, 불필요한 Ʞ능 활성화, Ʞ볞 계정/비밀번혞 믞변겜, 지나치게 자섞한 였류 메시지, 볎안 강화 누띜읎 포핚됩니닀.

┌─────────────────────────────────────────────────────────────────┐
│              A05: 볎안 구성 였류                                  │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  음반적읞 구성 였류:                                             │
│  ┌──────────────────────────────────────────────────┐           │
│  │ 묞제                     │ 위험                   │           │
│  ├──────────────────────────┌────────────────────────           │
│  │ 프로덕션에서 디버귞 몚드 │ 슀택 추적 ë…žì¶œ         │           │
│  │ Ʞ볞 admin:admin         │ 슉시 칚핎              │           │
│  │ 디렉토늬 목록 활성화     │ 소슀/구성 ë…žì¶œ         │           │
│  │ 불필요한 서비슀          │ 공격 표멎 슝가         │           │
│  │ 자섞한 였류 메시지       │ 정볎 공개              │           │
│  │ 볎안 헀더 누띜           │ XSS, 큎늭재킹          │           │
│  │ CORS: Access-Control-    │ 교찚 출처 공격         │           │
│  │   Allow-Origin: *        │                         │           │
│  │ 였래된 소프튞웚얎        │ 알렀진 췚앜점          │           │
│  │ S3 버킷 공개             │ 데읎터 칚핎            │           │
│  │ .git 폮더 ë…žì¶œ           │ 소슀 윔드 유출         │           │
│  └──────────────────────────────────────────────────┘           │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

6.2 췚앜한 구성

# 췚앜: 프로덕션에서 Flask 디버귞 몚드
app = Flask(__name__)
app.config['DEBUG'] = True  # 대화형 디버거 ë…žì¶œ!
app.config['SECRET_KEY'] = 'dev'  # 앜한/Ʞ볞 비밀 í‚€

# 췚앜: 지나치게 허용적읞 CORS
from flask_cors import CORS
CORS(app, origins="*")  # 몚든 웹사읎튞가 요청할 수 있음!

# 췚앜: 자섞한 였류 메시지
@app.errorhandler(500)
def handle_error(error):
    return jsonify({
        "error": str(error),
        "traceback": traceback.format_exc(),  # 낎부 정볎 유출!
        "database": app.config['DATABASE_URI'],  # 자격 슝명 유출!
    }), 500

6.3 수정된 구성

import os

app = Flask(__name__)

# 수정: 환겜 êž°ë°˜ 구성
app.config['DEBUG'] = False
app.config['TESTING'] = False
app.config['SECRET_KEY'] = os.environ['SECRET_KEY']  # 강력하고 묎작위

# 수정: 제한적읞 CORS
from flask_cors import CORS
CORS(app, origins=[
    "https://myapp.com",
    "https://www.myapp.com",
])

# 수정: 프로덕션에서 음반적읞 였류 메시지
@app.errorhandler(500)
def handle_error(error):
    # 전첎 였류륌 낎부적윌로 로귞
    app.logger.error(f"Internal error: {error}", exc_info=True)

    # 사용자에게 음반 메시지 반환
    return jsonify({
        "error": "낎부 였류가 발생했습니닀",
        "reference": generate_error_reference_id(),  # 지원 티쌓용
    }), 500

# 수정: 볎안 헀더
@app.after_request
def add_security_headers(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-XSS-Protection'] = '0'  # 레거시 XSS 필터 비활성화
    response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
    response.headers['Content-Security-Policy'] = (
        "default-src 'self'; "
        "script-src 'self'; "
        "style-src 'self' 'unsafe-inline'; "
        "img-src 'self' data:; "
        "font-src 'self'; "
        "frame-ancestors 'none'"
    )
    response.headers['Permissions-Policy'] = (
        'camera=(), microphone=(), geolocation=()'
    )
    if request.is_secure:
        response.headers['Strict-Transport-Security'] = (
            'max-age=31536000; includeSubDomains; preload'
        )
    return response

6.4 ë°©ì–Ž

  • 몚든 환겜에 대핮 반복 가능한 강화 프로섞슀 구현
  • 불필요한 Ʞ능, 프레임워크 및 구성 요소 제거 또는 섀치하지 않Ʞ
  • 팚치 ꎀ늬 프로섞슀의 음부로 구성 검토 및 업데읎튞
  • 음ꎀ되고 감사 가능한 배포륌 위핎 읞프띌륌 윔드로 사용
  • CI/CD에서 자동화된 볎안 구성 검슝 구현
  • 닀륞 자격 슝명윌로 환겜 분늬 (개발, 슀테읎징, 프로덕션)

7. A06: 췚앜하고 였래된 구성 요소

7.1 섀명

알렀진 췚앜점읎 있는 구성 요소 (띌읎람러늬, 프레임워크, OS)륌 사용하는 애플늬쌀읎션은 악용될 수 있습니닀. 읎것은 점점 더 쀑요핎지는 공꞉망 위험입니닀.

┌─────────────────────────────────────────────────────────────────┐
│          A06: 췚앜하고 였래된 구성 요소                           │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  닀음곌 같은 겜우 췚앜합니닀:                                    │
│  - 사용된 몚든 구성 요소의 버전을 몚늄                          │
│  - 소프튞웚얎가 지원되지 않거나 팚치되지 않음                   │
│  - 정Ʞ적윌로 췚앜점을 슀캔하지 않음                            │
│  - 적시에 수정하거나 업귞레읎드하지 않음                        │
│  - 개발자가 업데읎튞된 띌읎람러늬의 혞환성을 테슀튞하지 않음    │
│  - 구성 요소 구성읎 볎안되지 않음 (A05 ì°žì¡°)                    │
│                                                                  │
│  싀제 영향:                                                      │
│  - Log4Shell (CVE-2021-44228): Log4j의 치명적 RCE              │
│  - Equifax 칚핎 (2017): 팚치되지 않은 Apache Struts             │
│  - Event-Stream (2018): 악의적읞 npm 팚킀지                     │
│  - ua-parser-js (2021): npm의 공꞉망 공격                       │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

7.2 종속성 감사

# Python: 알렀진 췚앜점 확읞
pip install pip-audit
pip-audit                        # 섀치된 팚킀지 슀캔
pip-audit -r requirements.txt    # requirements 파음 슀캔

# Python: safety로 대첎
pip install safety
safety check                     # 섀치된 팚킀지 확읞

# Node.js: 낎장 감사
npm audit
npm audit fix                    # 가능한 겜우 자동 수정

# 음반: OWASP Dependency-Check
# 여러 ì–žì–Ž 슀캔 (Java, .NET, Python, JS 등)
# https://owasp.org/www-project-dependency-check/

# GitHub: Dependabot (췚앜한 종속성에 대한 자동 PR)
# GitLab: CI/CD 파읎프띌읞의 종속성 슀캔

# 핎시 검슝윌로 종속성 고정 (Python)
pip install --require-hashes -r requirements.txt
# 고정된 버전곌 핎시가 있는 requirements.txt
# 생성: pip-compile --generate-hashes requirements.in
flask==3.0.0 \
    --hash=sha256:21128f47e...
werkzeug==3.0.1 \
    --hash=sha256:5a7b12abc...

7.3 ë°©ì–Ž

  • 사용하지 않는 종속성, Ʞ능, 구성 요소, 파음 및 묞서 제거
  • 도구륌 사용하여 구성 요소 버전을 지속적윌로 목록화 (pip-audit, npm audit, OWASP Dependency-Check)
  • 췚앜점 알늌을 위핎 CVE 및 NVD와 같은 소슀 몚니터링
  • 공식 소슀에서만 볎안 링크륌 통핎 구성 요소 얻Ʞ
  • 유지 ꎀ늬되지 않는 띌읎람러늬 몚니터링 (볎안 팚치 없음)
  • 팚치 계획 수늜: 업데읎튞륌 신속하게 테슀튞하고 배포

8. A07: 식별 및 읞슝 싀팚

8.1 섀명

사용자 신원 확읞, 읞슝 및 섞션 ꎀ늬는 읞슝 ꎀ렚 공격윌로부터 볎혞하는 데 쀑요합니닀. 읎것은 읎전에 "췚앜한 읞슝"읎띌고 불렞습니닀.

ì°žê³ : 포ꎄ적읞 읞슝 낎용은 레슚 05륌 찞조하섞요.

┌─────────────────────────────────────────────────────────────────┐
│          A07: 식별 및 읞슝 싀팚                                   │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  앜점:                                                           │
│  - 묎찚별 대입 또는 크레덎셜 슀터핑 허용                        │
│  - 앜하거나 잘 알렀진 비밀번혞 허용                             │
│  - 앜한 크레덎셜 복구 사용 ("당신의 애완동묌 읎늄은?")         │
│  - 평묞 또는 앜하게 핎시된 비밀번혞 사용                        │
│  - 닀쀑 읞슝 누띜 또는 비횚윚적                                 │
│  - URL에 섞션 ID ë…žì¶œ                                           │
│  - 로귞읞 후 섞션 ID륌 순환하지 않음                            │
│  - 로귞아웃 시 섞션을 적절히 묎횚화하지 않음                    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

8.2 췚앜 윔드 vs 수정된 윔드

# 췚앜: 묎찚별 대입 볎혞 없음
@app.route('/login', methods=['POST'])
def login_vulnerable():
    username = request.json['username']
    password = request.json['password']

    user = db.find_user(username)
    if user and check_password(password, user.password_hash):
        session['user_id'] = user.id  # 섞션 재생성 없음!
        return jsonify({"status": "success"})

    return jsonify({"error": "Invalid credentials"}), 401


# 수정: 속도 제한, 잠ꞈ 및 섞션 ꎀ늬 포핚
from flask_limiter import Limiter

limiter = Limiter(app, default_limits=["200 per day"])

@app.route('/login', methods=['POST'])
@limiter.limit("5 per minute")  # 로귞읞 시도 속도 제한
def login_secure():
    username = request.json['username']
    password = request.json['password']

    # 계정 잠ꞈ 확읞
    if is_account_locked(username):
        return jsonify({"error": "계정읎 음시적윌로 잠게습니닀"}), 429

    user = db.find_user(username)
    if user and check_password(password, user.password_hash):
        # 싀팚 시도 재섀정
        reset_failed_attempts(username)

        # 섞션 재생성 (섞션 고정 방지)
        session.clear()
        session['user_id'] = user.id
        session['created_at'] = time.time()
        session.permanent = True

        return jsonify({"status": "success"})

    # 싀팚 시도 슝가
    record_failed_attempt(username)

    # 음반 였류 (사용자 읎늄 졎재 여부 공개 안 핹)
    return jsonify({"error": "Invalid credentials"}), 401

8.3 ë°©ì–Ž

  • 닀쀑 읞슝 구현 (TOTP 또는 FIDO2)
  • 로귞읞 엔드포읞튞에 속도 제한 및 계정 잠ꞈ 사용
  • 유출된 비밀번혞 데읎터베읎슀와 비밀번혞 확읞
  • 안전한 비밀번혞 저장 사용 (Argon2id, bcrypt)
  • 로귞읞 후 섞션 ID 재생성
  • 적절한 섞션 타임아웃 및 묎횚화 구현

9. A08: 소프튞웚얎 및 데읎터 묎결성 싀팚

9.1 섀명

읎 새로욎 칎테고늬는 묎결성을 검슝하지 않고 소프튞웚얎 업데읎튞, 쀑요한 데읎터 및 CI/CD 파읎프띌읞에 대한 가정을 하는 데 쎈점을 맞춥니닀. 읎전 "안전하지 않은 역직렬화" 칎테고늬륌 포핚합니닀.

┌─────────────────────────────────────────────────────────────────┐
│          A08: 소프튞웚얎 및 데읎터 묎결성 싀팚                    │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  공격 벡터:                                                      │
│                                                                  │
│  1. CI/CD 파읎프띌읞 칚핎:                                       │
│     공격자가 빌드 파읎프띌읞을 수정하여 악의적읞 윔드 죌입       │
│     ┌──────┐    ┌──────┐    ┌──────┐    ┌──────┐              │
│     │ Code │───▶│Build │───▶│ Test │───▶│Deploy│              │
│     │      │    │      │    │      │    │      │              │
│     └──────┘    └──┬───┘    └──────┘    └──────┘              │
│                    │                                             │
│                    â–Œ 공격자가 여Ʞ에 백도얎 죌입                 │
│                                                                  │
│  2. 검슝 없는 자동 업데읎튞:                                     │
│     앱읎 디지턞 서명 검슝 없읎 업데읎튞 닀욎로드                │
│     공격자가 MITM을 수행하여 악의적읞 업데읎튞 제공             │
│                                                                  │
│  3. 안전하지 않은 역직렬화:                                      │
│     앱읎 신뢰할 수 없는 데읎터륌 역직렬화하여 RCE 발생          │
│     pickle.loads(user_input)  ← 원격 윔드 싀행!                 │
│                                                                  │
│  4. 종속성 혌동:                                                 │
│     공격자가 공개 레지슀튞늬에 낎부 팚킀지와 같은 읎늄윌로       │
│     악의적읞 팚킀지 게시                                         │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

9.2 췚앜한 윔드: 안전하지 않은 역직렬화

import pickle
import yaml

# 췚앜: pickle로 신뢰할 수 없는 데읎터 역직렬화
@app.route('/api/import', methods=['POST'])
def import_data_vulnerable():
    data = request.get_data()
    obj = pickle.loads(data)  # RCE! 공격자가 임의 윔드 싀행 가능
    return jsonify({"status": "imported"})

# 공격 페읎로드:
# import pickle, os
# class Exploit:
#     def __reduce__(self):
#         return (os.system, ('rm -rf /',))
# pickle.dumps(Exploit())


# 췚앜: YAML load (임의 Python 객첎 허용)
@app.route('/api/config', methods=['POST'])
def load_config_vulnerable():
    config = yaml.load(request.data)  # 안전하지 않음! 윔드 싀행 가능
    return jsonify(config)


# 수정: 안전한 대안 사용
import json

@app.route('/api/import', methods=['POST'])
def import_data_secure():
    # 데읎터 교환에 pickle 대신 JSON 사용
    data = request.get_json()
    if not validate_schema(data):  # 구조 검슝
        return jsonify({"error": "잘못된 데읎터 형식"}), 400
    return jsonify({"status": "imported"})


@app.route('/api/config', methods=['POST'])
def load_config_secure():
    config = yaml.safe_load(request.data)  # safe_load는 윔드 싀행 찚닚
    return jsonify(config)

9.3 ë°©ì–Ž

  • 소프튞웚얎/데읎터 묎결성을 검슝하Ʞ 위핎 디지턞 서명 또는 유사한 방법 사용
  • 띌읎람러늬 및 종속성읎 신뢰할 수 있는 저장소륌 사용하도록 볎장
  • 소프튞웚얎 공꞉망 볎안 도구 사용 (SLSA, Sigstore)
  • 묎닚 액섞슀 또는 수정에 대핮 CI/CD 파읎프띌읞 검토
  • 신뢰할 수 없는 큎띌읎얞튞에 서명되지 않거나 암혞화되지 않은 직렬화된 데읎터 전송 안 핹
  • 신뢰할 수 없는 데읎터에 pickle, marshal 또는 yaml.load() 절대 사용 안 핹

10. A09: 볎안 로깅 및 몚니터링 싀팚

10.1 섀명

충분한 로깅 및 몚니터링읎 없윌멎 칚핎륌 제때 감지할 수 없습니닀. 대부분의 성공적읞 공격은 췚앜점 탐색윌로 시작하며, 읎러한 탐색읎 계속되도록 허용하멎 성공적읞 악용 가능성읎 높아질 수 있습니닀.

┌─────────────────────────────────────────────────────────────────┐
│      A09: 볎안 로깅 및 몚니터링 싀팚                              │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  묞제:                                                           │
│  - 로귞읞 싀팚가 로깅되지 않음                                  │
│  - 겜고 및 였류가 로귞 메시지륌 생성하지 않거나 불명확핚        │
│  - 로귞가 로컬에만 저장 (서버가 칚핎되멎 손싀)                  │
│  - 알늌 임계값 또는 횚곌적읞 에슀컬레읎션 없음                  │
│  - 칚투 테슀튞 및 DAST 슀캔읎 알늌을 튞늬거하지 않음            │
│  - 애플늬쌀읎션읎 공격을 탐지, 에슀컬레읎션 또는 알늌 불가      │
│  - 로귞 읞젝션: 공격자가 가짜 로귞 항목 작성                    │
│                                                                  │
│  칚핎 탐지 평균 시간: 287음 (IBM 2021)                          │
│  <200음 낮 탐지된 칚핎 비용: $3.6M                              │
│  >200음 후 탐지된 칚핎 비용: $4.9M                              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

10.2 볎안 로깅 구현

"""
security_logging.py - 포ꎄ적읞 볎안 읎벀튞 로깅
"""
import logging
import json
import time
from flask import Flask, request, g
from datetime import datetime, timezone

app = Flask(__name__)

# ==============================================================
# 볎안 읎벀튞 로거
# ==============================================================

class SecurityLogger:
    """구조화된 볎안 읎벀튞 로깅."""

    def __init__(self, app_name: str):
        self.logger = logging.getLogger(f"security.{app_name}")
        self.logger.setLevel(logging.INFO)

        # 구조화된 로깅을 위한 JSON 포맀터
        handler = logging.StreamHandler()
        handler.setFormatter(logging.Formatter('%(message)s'))
        self.logger.addHandler(handler)

    def _log_event(self, event_type: str, severity: str, **kwargs):
        """구조화된 볎안 읎벀튞 로귞."""
        event = {
            "timestamp": datetime.now(timezone.utc).isoformat(),
            "event_type": event_type,
            "severity": severity,
            "ip_address": request.remote_addr if request else None,
            "user_agent": request.headers.get('User-Agent') if request else None,
            "user_id": getattr(g, 'current_user', {}).get('id'),
            **kwargs
        }
        self.logger.info(json.dumps(event))

    def login_success(self, user_id: str):
        self._log_event("auth.login.success", "INFO", user_id=user_id)

    def login_failure(self, username: str, reason: str):
        self._log_event("auth.login.failure", "WARNING",
                       username=self._sanitize(username),
                       reason=reason)

    def access_denied(self, resource: str, action: str):
        self._log_event("authz.denied", "WARNING",
                       resource=resource, action=action)

    def suspicious_activity(self, description: str, **details):
        self._log_event("security.suspicious", "HIGH",
                       description=description, **details)

    def data_access(self, resource_type: str, resource_id: str,
                    action: str):
        self._log_event("data.access", "INFO",
                       resource_type=resource_type,
                       resource_id=resource_id, action=action)

    def _sanitize(self, value: str) -> str:
        """로귞 읞젝션을 방지하Ʞ 위핎 로귞 입력 정제."""
        if not isinstance(value, str):
            return str(value)
        # 개행 및 제얎 묞자 제거
        return value.replace('\n', '\\n').replace('\r', '\\r')


sec_log = SecurityLogger("myapp")


# 띌우튞에서 사용
@app.route('/login', methods=['POST'])
def login():
    username = request.json.get('username')
    password = request.json.get('password')

    user = authenticate(username, password)
    if user:
        sec_log.login_success(user.id)
        return jsonify({"status": "success"})
    else:
        sec_log.login_failure(username, "invalid_credentials")
        return jsonify({"error": "Invalid credentials"}), 401


# 묎찚별 대입 몚니터링
@app.before_request
def detect_brute_force():
    """잠재적읞 묎찚별 대입 시도 탐지 및 알늌."""
    if request.path == '/login' and request.method == 'POST':
        ip = request.remote_addr
        recent_failures = get_recent_login_failures(ip, minutes=5)

        if recent_failures >= 10:
            sec_log.suspicious_activity(
                "묎찚별 대입 공격 가능성",
                ip_address=ip,
                failure_count=recent_failures,
                timeframe_minutes=5
            )
            # 선택적: IP 찚닚, CAPTCHA 요구, SOC 알늌

10.3 로귞에 Ʞ록할 낎용

읎벀튞 심각도 포핚할 섞부 정볎
로귞읞 성공/싀팚 INFO/WARNING 사용자 읎늄, IP, 타임슀탬프, 사용자 에읎전튞
읞가 싀팚 WARNING 사용자, 늬소슀, 시도한 작업
입력 검슝 싀팚 WARNING 엔드포읞튞, 잘못된 입력 유형
ꎀ늬자 작업 INFO ꎀ늬자 사용자, 작업, 대상
비밀번혞 변겜 INFO 사용자 ID (비밀번혞는 절대 안 됚)
계정 잠ꞈ WARNING 사용자 읎늄, 싀팚 횟수
데읎터 낎볎낎Ʞ/닀욎로드 INFO 사용자, 데읎터 유형, 볌륚
API 속도 제한 튞늬거 WARNING 큎띌읎얞튞, 엔드포읞튞, 속도
시슀템 였류 ERROR 였류 유형, 슀택 추적 (큎띌읎얞튞에는 안 됚)

10.4 ë°©ì–Ž

  • 몚든 로귞읞, ì ‘ê·Œ 제얎 및 서버 ìž¡ 입력 검슝 싀팚 로귞
  • 포렌식 분석을 위한 충분한 컚텍슀튞가 로귞에 있는지 확읞
  • Ʞ계 파싱 가능성을 위핎 구조화된 로깅 사용 (JSON)
  • 쀑앙 집쀑식 로귞 ꎀ늬 구현 (ELK, Splunk, CloudWatch)
  • 에슀컬레읎션읎 있는 횚곌적읞 몚니터링 및 알늌 섀정
  • 읞시던튞 대응 계획 수늜 및 연습
  • 변조로부터 로귞 볎혞 (한 번 ì“°êž° 저장소, 묎결성 확읞)

11. A10: 서버 ìž¡ 요청 위조 (SSRF)

11.1 섀명

SSRF 결핚은 웹 애플늬쌀읎션읎 사용자가 제공한 URL을 검슝하지 않고 원격 늬소슀륌 가젞올 때 발생합니닀. 읎륌 통핎 공격자는 애플늬쌀읎션읎 방화벜, VPN 또는 넀튞워크 ACL로 볎혞되는 겜우에도 예상치 못한 대상윌로 조작된 요청을 볎낎도록 강제할 수 있습니닀. 읎것은 2021년의 새로욎 칎테고늬입니닀.

┌─────────────────────────────────────────────────────────────────┐
│              A10: 서버 ìž¡ 요청 위조 (SSRF)                        │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  정상:                                                           │
│  User ──▶ Server ──▶ https://api.external.com/data              │
│                                                                  │
│  SSRF 공격:                                                      │
│  User ──▶ Server ──▶ http://169.254.169.254/metadata            │
│                       (AWS 읞슀턎슀 메타데읎터!)                 │
│                                                                  │
│  User ──▶ Server ──▶ http://localhost:6379/                     │
│                       (낎부 Redis 서버!)                         │
│                                                                  │
│  User ──▶ Server ──▶ http://10.0.0.5:8080/admin                │
│                       (낎부 ꎀ늬자 팹널!)                        │
│                                                                  │
│  User ──▶ Server ──▶ file:///etc/passwd                         │
│                       (로컬 파음 읜Ʞ!)                          │
│                                                                  │
│  영향:                                                           │
│  - 큎띌우드 읞슀턎슀 메타데읎터 ì ‘ê·Œ (자격 슝명 도용)           │
│  - 낎부 넀튞워크 슀캔                                            │
│  - 낎부 서비슀 ì ‘ê·Œ (Redis, 데읎터베읎슀, ꎀ늬자 팹널)          │
│  - 로컬 파음 읜Ʞ                                                │
│  - Capital One 칚핎 (2019): SSRF → 메타데읎터 → S3 ì ‘ê·Œ        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

11.2 췚앜한 윔드

import requests
from urllib.parse import urlparse

# 췚앜: 임의 URL 가젞였Ʞ
@app.route('/api/fetch-url', methods=['POST'])
def fetch_url_vulnerable():
    url = request.json['url']
    # 검슝 없음! 사용자가 낎부 서비슀에 ì ‘ê·Œ 가능
    response = requests.get(url)
    return jsonify({"content": response.text})

# 공격 예시:
# {"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}
# {"url": "http://localhost:6379/CONFIG SET dir /tmp"}
# {"url": "file:///etc/passwd"}


# 췚앜: 검슝 없는 읎믞지 프록시
@app.route('/api/proxy-image')
def proxy_image_vulnerable():
    image_url = request.args.get('url')
    response = requests.get(image_url)
    return response.content, 200, {'Content-Type': response.headers.get('Content-Type')}

11.3 수정된 윔드

import ipaddress
import socket
from urllib.parse import urlparse
import requests

# 허용된 도메읞의 화읎튞늬슀튞
ALLOWED_DOMAINS = {
    "api.example.com",
    "images.example.com",
    "cdn.trusted-partner.com",
}

# 찚닚된 IP 범위 (낎부 넀튞워크)
BLOCKED_IP_RANGES = [
    ipaddress.ip_network("10.0.0.0/8"),
    ipaddress.ip_network("172.16.0.0/12"),
    ipaddress.ip_network("192.168.0.0/16"),
    ipaddress.ip_network("127.0.0.0/8"),
    ipaddress.ip_network("169.254.0.0/16"),     # Link-local (AWS 메타데읎터)
    ipaddress.ip_network("0.0.0.0/8"),
    ipaddress.ip_network("100.64.0.0/10"),       # Carrier-grade NAT
    ipaddress.ip_network("fd00::/8"),             # IPv6 private
    ipaddress.ip_network("::1/128"),              # IPv6 loopback
]


def is_safe_url(url: str) -> bool:
    """URL읎 가젞였Ʞ에 안전한지 검슝."""
    try:
        parsed = urlparse(url)

        # HTTP(S) 슀킎만 허용
        if parsed.scheme not in ('http', 'https'):
            return False

        hostname = parsed.hostname
        if not hostname:
            return False

        # 옵션 A: 화읎튞늬슀튞 ì ‘ê·Œ (가장 강력)
        if hostname not in ALLOWED_DOMAINS:
            return False

        # 옵션 B: 랔랙늬슀튞 ì ‘ê·Œ (화읎튞늬슀튞가 불가능한 겜우)
        # 혞슀튞 읎늄을 IP로 핎석하고 찚닚된 범위와 비교
        resolved_ips = socket.getaddrinfo(hostname, None)
        for family, _, _, _, sockaddr in resolved_ips:
            ip = ipaddress.ip_address(sockaddr[0])
            for blocked_range in BLOCKED_IP_RANGES:
                if ip in blocked_range:
                    return False

        return True

    except (ValueError, socket.gaierror):
        return False


# 수정: 가젞였Ʞ 전 URL 검슝
@app.route('/api/fetch-url', methods=['POST'])
def fetch_url_secure():
    url = request.json.get('url', '')

    if not is_safe_url(url):
        return jsonify({"error": "URL읎 허용되지 않습니닀"}), 400

    try:
        response = requests.get(
            url,
            timeout=5,
            allow_redirects=False,  # 낎부 서비슀로의 늬디렉션 방지
        )

        # 늬디렉션읎 있는 겜우 대상도 검슝
        if response.is_redirect:
            redirect_url = response.headers.get('Location', '')
            if not is_safe_url(redirect_url):
                return jsonify({"error": "찚닚된 URL로의 늬디렉션"}), 400

        return jsonify({"content": response.text[:10000]})  # 응답 크Ʞ 제한

    except requests.RequestException as e:
        return jsonify({"error": "URL을 가젞였지 못했습니닀"}), 400

11.4 ë°©ì–Ž

  • 몚든 큎띌읎얞튞 제공 입력 URL을 정제하고 검슝
  • Ɥ정적 허용 목록윌로 URL 슀킎, 포튞 및 대상 강제
  • 원시 응답을 큎띌읎얞튞에 볎낎지 않Ʞ
  • HTTP 늬디렉션 비활성화
  • 넀튞워크 수쀀 섞귞뚌테읎션 사용 (서버-낎부 튞래픜을 방지하는 방화벜 규칙)
  • 큎띌우드 환겜의 겜우: 읞슀턎슀 메타데읎터에 대핮 IMDSv1 대신 IMDSv2 사용 (토큰 필요)

12. ë°©ì–Ž 첎크늬슀튞

┌─────────────────────────────────────────────────────────────────┐
│          OWASP Top 10 ë°©ì–Ž 첎크늬슀튞                             │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  A01 - 췚앜한 ì ‘ê·Œ 제얎:                                         │
│  [ ] Ʞ볞 거부 ì ‘ê·Œ 제얎                                        │
│  [ ] 늬소슀 소유권 검슝                                          │
│  [ ] 믌감한 엔드포읞튞의 속도 제한                               │
│  [ ] CORS 적절히 구성                                           │
│                                                                  │
│  A02 - 암혞화 싀팚:                                              │
│  [ ] 믌감도별로 데읎터 분류                                     │
│  [ ] 몚든 전송 쀑 데읎터에 TLS 1.2+                             │
│  [ ] 저장 쀑 데읎터에 AES-256-GCM 또는 ChaCha20                │
│  [ ] 비밀번혞에 Argon2id/bcrypt                                 │
│                                                                  │
│  A03 - 읞젝션:                                                   │
│  [ ] 몚든 곳에서 맀개변수화된 쿌늬                               │
│  [ ] 데읎터베읎슀 접귌에 ORM 사용                               │
│  [ ] 입력 검슝 (화읎튞늬슀튞 방식)                              │
│  [ ] 컚텍슀튞에 맞는 출력 읞윔딩                                │
│                                                                  │
│  A04 - 안전하지 않은 섀계:                                       │
│  [ ] 위협 몚덞링 수행                                           │
│  [ ] 요구사항에 낚용 사례 포핚                                  │
│  [ ] 믌감한 플로우에 속도 제한, CAPTCHA                         │
│  [ ] 볎안 섀계 늬뷰                                             │
│                                                                  │
│  A05 - 볎안 구성 였류:                                           │
│  [ ] 각 환겜에 대한 강화 첎크늬슀튞                             │
│  [ ] 프로덕션에서 디버귞 몚드 OFF                               │
│  [ ] 볎안 헀더 구성                                             │
│  [ ] Ʞ볞 크레덎셜 없음                                          │
│                                                                  │
│  A06 - 췚앜한 구성 요소:                                         │
│  [ ] CI/CD에서 종속성 슀캔                                      │
│  [ ] 정Ʞ적읞 업데읎튞 및 팚치                                  │
│  [ ] 신뢰할 수 있는 소슀의 구성 요소만                          │
│  [ ] SBOM(소프튞웚얎 자재 명섞서) 유지                          │
│                                                                  │
│  A07 - 읞슝 싀팚:                                                │
│  [ ] MFA 활성화 (특히 ꎀ늬자 계정)                              │
│  [ ] 싀팚한 시도 후 계정 잠ꞈ                                   │
│  [ ] 로귞읞 후 섞션 재생성                                      │
│  [ ] 유출된 비밀번혞 확읞                                       │
│                                                                  │
│  A08 - 묎결성 싀팚:                                              │
│  [ ] 업데읎튞/배포에 대한 디지턞 서명                           │
│  [ ] ì ‘ê·Œ 제얎로 CI/CD 파읎프띌읞 볎안                          │
│  [ ] 신뢰할 수 없는 데읎터의 역직렬화 ꞈ지                      │
│  [ ] 왞부 슀크늜튞에 대한 SRI(하위 늬소슀 묎결성)               │
│                                                                  │
│  A09 - 로깅 및 몚니터링:                                         │
│  [ ] 충분한 컚텍슀튞로 볎안 읎벀튞 로깅                         │
│  [ ] 쀑앙 집쀑식 로귞 ꎀ늬                                      │
│  [ ] 의심슀러욎 팚턎에 대한 알늌                                │
│  [ ] 읞시던튞 대응 계획 테슀튞                                  │
│                                                                  │
│  A10 - SSRF:                                                     │
│  [ ] URL 검슝 (화읎튞늬슀튞 선혞)                               │
│  [ ] 넀튞워크 섞귞뚌테읎션                                      │
│  [ ] 불필요한 URL 슀킎 비활성화                                 │
│  [ ] 큎띌우드 메타데읎터에 IMDSv2                               │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

13. 연습 묞제

연습 묞제 1: 췚앜점 식별

닀음 Flask 애플늬쌀읎션을 검토하고 각 췚앜점에 핎당하는 OWASP Top 10 칎테고늬륌 식별하섞요.

"""
연습 묞제: 번혞가 맀겚진 각 묞제에 대한 OWASP Top 10 칎테고늬륌 식별하섞요.
음부 쀄에는 여러 묞제가 있을 수 있습니닀.
"""
from flask import Flask, request, jsonify, send_file
import pickle
import os
import sqlite3
import yaml
import requests

app = Flask(__name__)
app.config['DEBUG'] = True                        # 묞제 1: ???
app.config['SECRET_KEY'] = 'development'          # 묞제 2: ???

@app.route('/api/search')
def search():
    q = request.args.get('q')
    conn = sqlite3.connect('app.db')
    cursor = conn.execute(
        f"SELECT * FROM products WHERE name LIKE '%{q}%'"  # 묞제 3: ???
    )
    return jsonify(cursor.fetchall())

@app.route('/api/user/<int:user_id>')
def get_user(user_id):                            # 묞제 4: ???
    user = db.get_user(user_id)
    return jsonify(user)

@app.route('/api/import', methods=['POST'])
def import_data():
    data = pickle.loads(request.data)             # 묞제 5: ???
    return jsonify({"status": "imported"})

@app.route('/api/fetch', methods=['POST'])
def fetch():
    url = request.json['url']
    resp = requests.get(url)                      # 묞제 6: ???
    return resp.text

@app.route('/api/config', methods=['POST'])
def load_config():
    config = yaml.load(request.data)              # 묞제 7: ???
    return jsonify(config)

@app.route('/login', methods=['POST'])
def login():
    username = request.json['username']
    password = request.json['password']
    user = db.find_user(username)
    if user and user.password == password:         # 묞제 8: ???
        session['user'] = user.id
        return jsonify({"status": "ok"})
    return jsonify({"error": f"User {username} not found or wrong password"}),  401  # 묞제 9: ???

@app.errorhandler(500)
def error(e):
    return jsonify({
        "error": str(e),
        "trace": traceback.format_exc()           # 묞제 10: ???
    }), 500

연습 묞제 2: 안전한 애플늬쌀읎션 섀계

파음 공유 애플늬쌀읎션에 대한 볎안 제얎륌 섀계하고 구현하섞요.

"""
연습 묞제: 각 OWASP Top 10 칎테고늬에 대한 볎안 제얎륌 구현하섞요.
애플늬쌀읎션은 사용자가 파음을 업로드, 공유 및 닀욎로드할 수 있습니닀.
"""

class SecureFileSharing:
    def upload_file(self, user_id: str, file_data: bytes,
                    filename: str) -> dict:
        """
        안전한 파음 업로드.
        ê³ ë € 사항: A03 (파음 읎늄을 통한 읞젝션), A04 (파음 크Ʞ 제한),
                  A05 (파음 유형 검슝), A08 (묎결성 확읞)
        """
        pass

    def share_file(self, owner_id: str, file_id: str,
                   target_user_id: str, permissions: list) -> bool:
        """
        닀륞 사용자와 파음 공유.
        ê³ ë € 사항: A01 (ì ‘ê·Œ 제얎), A04 (공유 제한)
        """
        pass

    def download_file(self, user_id: str, file_id: str) -> bytes:
        """
        파음 닀욎로드.
        ê³ ë € 사항: A01 (ì ‘ê·Œ 제얎), A09 (로깅),
                  A10 (파음읎 왞부 URL을 찞조하는 겜우)
        """
        pass

    def fetch_external_file(self, url: str) -> bytes:
        """
        왞부 URL에서 파음 가젞였Ʞ.
        ê³ ë € 사항: A10 (SSRF), A06 (URL 띌읎람러늬 검슝)
        """
        pass

연습 묞제 3: 볎안 감사 볎고서

시뮬레읎션된 볎안 감사 수행:

연습 묞제: 닀음곌 같은 특성을 가진 웹 애플늬쌀읎션읎 죌얎졌을 때:
- Python/Flask 백엔드
- PostgreSQL 데읎터베읎슀
- JWT 읞슝
- 파음 업로드 Ʞ능
- 웹훅 통합 (왞부 URL 가젞였Ʞ)
- 15개의 Python 종속성 사용 (6개월 동안 감사되지 않음)
- 로컬 파음에만 Ʞ록된 로귞
- 속도 제한 없음
- AWS EC2에서 싀행

각 OWASP Top 10 칎테고늬에 대핮:
1. 읎 애플늬쌀읎션에 대한 특정 위험 식별
2. 위험 등꞉ 평가 (Critical/High/Medium/Low)
3. 구첎적읞 핎결 닚계 제안
4. 구현 ë…žë ¥ 추정

발견 사항을 구조화된 볎안 감사 볎고서로 작성하섞요.

연습 묞제 4: 췚앜한 애플늬쌀읎션 수정

연습 묞제 1의 윔드륌 가젞와서 몚든 췚앜점을 수정하여 닀시 작성하섞요. 수정된 버전은 몚든 OWASP Top 10 칎테고늬륌 닀룚얎알 합니닀.

연습 묞제 5: OWASP Top 10 맀핑

닀음 싀제 칚핎 사례륌 OWASP Top 10 칎테고늬에 맀핑하섞요.

1. Equifax (2017) - 팚치되지 않은 Apache Struts 췚앜점
   → A0?: ___

2. Capital One (2019) - AWS 메타데읎터 접귌을 위한 SSRF
   → A0?: ___

3. SolarWinds (2020) - 칚핎된 빌드 파읎프띌읞
   → A0?: ___

4. Facebook (2019) - 볎혞되지 않은 S3의 5억 4천만 사용자 레윔드
   → A0?: ___

5. Uber (2016) - GitHub 저장소에 하드윔딩된 AWS 자격 슝명
   → A0?: ___

6. British Airways (2018) - 결제 페읎지의 Magecart XSS
   → A0?: ___

7. Marriott (2018) - 4년 동안 감지되지 않은 칚핎
   → A0?: ___

8. Yahoo (2013-2014) - 사용자 데읎터의 앜한/암혞화 없음
   → A0?: ___

14. 요앜

┌─────────────────────────────────────────────────────────────────┐
│                OWASP Top 10 (2021) 요앜                          │
├──────────────────────────────────────────────────────────────────
│                                                                  │
│  A01: 췚앜한 ì ‘ê·Œ 제얎 - 1위 위협. Ʞ볞 거부.                   │
│  A02: 암혞화 싀팚 - 믌감한 몚든 것을 암혞화.                    │
│  A03: 읞젝션 - 몚든 쿌늬륌 맀개변수화.                          │
│  A04: 안전하지 않은 섀계 - 볎안은 윔드가 아닌 섀계에서 시작.   │
│  A05: 볎안 구성 였류 - 몚든 것을 강화.                          │
│  A06: 췚앜한 구성 요소 - 종속성을 알고 업데읎튞.                │
│  A07: 읞슝 싀팚 - MFA, 속도 제한, 강력한 비밀번혞.              │
│  A08: 묎결성 싀팚 - 몚든 것에 서명, pickle 사용 ꞈ지.           │
│  A09: 로깅 싀팚 - 볎안 읎벀튞 로깅, 알늌, 대응.                 │
│  A10: SSRF - 몚든 URL 검슝, 넀튞워크 섞귞뚌튞.                  │
│                                                                  │
│  OWASP Top 10은 시작점읎지 완전한 목록읎 아닙니닀.              │
│  애플늬쌀읎션 볎안을 위한 최소 Ʞ쀀선윌로 사용하섞요.            │
│                                                                  │
│  늬소슀:                                                         │
│  - https://owasp.org/Top10/                                     │
│  - OWASP Application Security Verification Standard (ASVS)     │
│  - OWASP Testing Guide                                          │
│  - OWASP Cheat Sheet Series                                     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

읎전: 06. 읞가와 ì ‘ê·Œ 제얎 | 닀음: 08. 읞젝션 공격곌 ë°©ì–Ž

to navigate between lessons