Skip to content

필사 모드: 애플리케이션 보안 엔지니어링 가이드 — OWASP Top 10, 인증, 암호화, DevSecOps

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

애플리케이션 보안 엔지니어링 가이드

소프트웨어가 비즈니스의 핵심이 된 시대, 보안은 선택이 아니라 생존의 문제입니다. 이 가이드는 OWASP Top 10부터 DevSecOps 파이프라인까지 애플리케이션 보안의 전 범위를 다룹니다.

1. 왜 보안이 중요한가

데이터 유출의 현실

IBM의 "Cost of a Data Breach Report"에 따르면, 2024년 기준 데이터 유출 한 건의 평균 비용은 약 488만 달러에 달합니다. 유출 사고의 주요 원인은 다음과 같습니다.

| 원인 | 비율 | 평균 비용 |

| --- | --- | --- |

| 피싱 공격 | 16% | 476만 달러 |

| 도난/유출된 인증정보 | 15% | 463만 달러 |

| 클라우드 설정 오류 | 12% | 414만 달러 |

| 제로데이 취약점 | 10% | 518만 달러 |

개발자의 보안 책임

보안은 더 이상 보안팀만의 책임이 아닙니다. "Shift Left" 패러다임에 따라, 개발 초기 단계에서 보안을 내재화해야 합니다.

- 코드 작성 단계에서 취약점을 방지하는 것이 사후 패치보다 6~100배 저렴합니다

- SDLC(소프트웨어 개발 수명 주기) 전체에서 보안을 고려해야 합니다

- 보안은 기능(feature)이 아니라 품질(quality)의 일부입니다

보안의 3대 원칙: CIA Triad

- **Confidentiality (기밀성)**: 인가된 사용자만 데이터에 접근 가능

- **Integrity (무결성)**: 데이터가 무단으로 변경되지 않음을 보장

- **Availability (가용성)**: 필요할 때 시스템과 데이터에 접근 가능

2. OWASP Top 10 (2021)

OWASP Top 10은 웹 애플리케이션에서 가장 치명적인 10가지 보안 취약점을 정리한 것입니다. 각각의 취약점과 방어법을 살펴봅니다.

A01: Broken Access Control (접근 제어 실패)

가장 흔한 취약점입니다. 인가되지 않은 사용자가 다른 사용자의 데이터에 접근하거나 관리자 기능을 수행할 수 있습니다.

**공격 시나리오**: URL 파라미터를 변경하여 다른 사용자의 주문 내역을 조회

**방어법**:

Flask에서 접근 제어 데코레이터

from functools import wraps

from flask import abort, g

def require_role(role):

def decorator(f):

@wraps(f)

def decorated_function(*args, **kwargs):

if not g.current_user or g.current_user.role != role:

abort(403)

return f(*args, **kwargs)

return decorated_function

return decorator

@app.route('/admin/users')

@require_role('admin')

def admin_users():

return get_all_users()

- 기본적으로 모든 접근을 거부하고, 명시적으로 허용하는 화이트리스트 방식을 사용합니다

- 서버 사이드에서 반드시 권한을 검증합니다

- IDOR(Insecure Direct Object References) 방지를 위해 UUID를 사용합니다

A02: Cryptographic Failures (암호화 실패)

민감 데이터가 평문으로 전송되거나 약한 암호화로 보호되는 경우입니다.

**방어법**:

- 전송 중 데이터: TLS 1.3 사용

- 저장 데이터: AES-256-GCM으로 암호화

- 비밀번호: bcrypt 또는 Argon2로 해싱

- MD5, SHA-1 같은 취약한 알고리즘을 사용하지 않습니다

A03: Injection (인젝션)

SQL, NoSQL, OS 명령어, LDAP 등의 인젝션 공격입니다.

**취약한 코드**:

절대 이렇게 하면 안 됩니다 - SQL Injection에 취약

query = "SELECT * FROM users WHERE id = " + user_input

**안전한 코드**:

파라미터화 쿼리 사용

cursor.execute("SELECT * FROM users WHERE id = %s", (user_input,))

ORM 사용 (SQLAlchemy)

user = User.query.filter_by(id=user_input).first()

A04: Insecure Design (안전하지 않은 설계)

설계 단계에서의 보안 결함입니다. 코드 수준이 아닌 아키텍처 수준의 문제입니다.

**방어법**:

- Threat Modeling 수행 (STRIDE, PASTA 방법론)

- 보안 설계 원칙 적용 (최소 권한, 심층 방어, 실패 안전)

- 비즈니스 로직에 대한 보안 시나리오 테스트

A05: Security Misconfiguration (보안 설정 오류)

기본 계정 미변경, 불필요한 기능 활성화, 디버그 모드 운영 환경 노출 등이 해당됩니다.

**체크리스트**:

- 기본 비밀번호를 변경했는가

- 불필요한 포트와 서비스를 비활성화했는가

- 에러 메시지에 스택 트레이스가 노출되지 않는가

- 보안 헤더(X-Frame-Options, X-Content-Type-Options)가 설정되었는가

A06: Vulnerable and Outdated Components (취약하고 오래된 컴포넌트)

알려진 취약점이 있는 라이브러리나 프레임워크를 사용하는 경우입니다.

**방어법**:

npm 보안 감사

npm audit

Python 의존성 검사

pip-audit

Go 취약점 검사

govulncheck ./...

A07: Identification and Authentication Failures (인증 실패)

약한 비밀번호 정책, 세션 관리 미흡, 브루트포스 공격 방치 등이 해당됩니다. 자세한 내용은 3장에서 다룹니다.

A08: Software and Data Integrity Failures (무결성 실패)

CI/CD 파이프라인, 소프트웨어 업데이트, 직렬화에서의 무결성 검증 부족입니다.

**방어법**:

- 디지털 서명으로 소프트웨어 무결성 검증

- SBOM(Software Bill of Materials) 관리

- CI/CD 파이프라인 보안 (코드 서명, 접근 제어)

A09: Security Logging and Monitoring Failures (로깅 및 모니터링 실패)

보안 이벤트를 기록하지 않거나, 기록하더라도 모니터링하지 않는 경우입니다.

**필수 로깅 항목**:

from datetime import datetime, timezone

security_logger = logging.getLogger('security')

def log_security_event(event_type, user_id, details):

event = {

"timestamp": datetime.now(timezone.utc).isoformat(),

"event_type": event_type,

"user_id": user_id,

"ip_address": request.remote_addr,

"user_agent": request.headers.get('User-Agent'),

"details": details

}

security_logger.warning(json.dumps(event))

사용 예시

log_security_event("LOGIN_FAILED", "user123", "Invalid password attempt 3")

log_security_event("PRIVILEGE_ESCALATION", "user456", "Attempted admin access")

A10: Server-Side Request Forgery (SSRF)

서버가 공격자가 지정한 URL로 요청을 보내도록 유도하는 공격입니다.

**방어법**:

- 허용된 URL 화이트리스트 적용

- 내부 네트워크 IP 대역(10.x, 172.16.x, 192.168.x)으로의 요청 차단

- DNS Rebinding 방어

3. 인증(Authentication)

인증은 사용자가 자신이 주장하는 사람인지 확인하는 과정입니다.

비밀번호 해싱

비밀번호는 절대 평문이나 가역 암호화로 저장하면 안 됩니다.

Argon2 - 현재 가장 권장되는 해싱 알고리즘

from argon2 import PasswordHasher

ph = PasswordHasher(

time_cost=3, # 반복 횟수

memory_cost=65536, # 64MB 메모리

parallelism=4, # 병렬 스레드 수

hash_len=32, # 해시 길이

salt_len=16 # 솔트 길이

)

해싱

hashed = ph.hash("user_password")

결과 예시: $argon2id$v=19$m=65536,t=3,p=4$...

검증

try:

ph.verify(hashed, "user_password")

print("비밀번호 일치")

except Exception:

print("비밀번호 불일치")

bcrypt - 널리 사용되는 대안

password = b"user_password"

salt = bcrypt.gensalt(rounds=12)

hashed = bcrypt.hashpw(password, salt)

검증

if bcrypt.checkpw(password, hashed):

print("비밀번호 일치")

다중 인증(MFA)

비밀번호만으로는 충분하지 않습니다. 최소 두 가지 인증 요소를 조합합니다.

| 인증 요소 | 설명 | 예시 |

| --- | --- | --- |

| 지식 (Something you know) | 사용자가 알고 있는 정보 | 비밀번호, PIN |

| 소유 (Something you have) | 사용자가 소유한 물건 | 스마트폰, 보안 키 |

| 생체 (Something you are) | 사용자의 신체 특징 | 지문, 얼굴 인식 |

TOTP (Time-based One-Time Password) 구현

비밀키 생성

secret = pyotp.random_base32()

QR 코드 URI 생성

totp_uri = pyotp.totp.TOTP(secret).provisioning_uri(

name="user@example.com",

issuer_name="MyApp"

)

검증

totp = pyotp.TOTP(secret)

is_valid = totp.verify("123456") # 사용자 입력 코드

패스키(WebAuthn/FIDO2)

비밀번호 없는 미래를 위한 인증 표준입니다.

- 공개키 암호화 기반으로 피싱에 강합니다

- 생체 인증 또는 PIN으로 로컬 인증 후, 서버에는 공개키만 전달됩니다

- Apple, Google, Microsoft 모두 지원합니다

// 패스키 등록 (브라우저 측)

const credential = await navigator.credentials.create({

publicKey: {

challenge: serverChallenge,

rp: { name: "MyApp", id: "myapp.com" },

user: {

id: userId,

name: "user@example.com",

displayName: "사용자"

},

pubKeyCredParams: [

{ alg: -7, type: "public-key" }, // ES256

{ alg: -257, type: "public-key" } // RS256

],

authenticatorSelection: {

authenticatorAttachment: "platform",

residentKey: "required",

userVerification: "required"

}

}

});

4. 인가(Authorization)

인가는 인증된 사용자가 어떤 리소스에 접근할 수 있는지 결정하는 과정입니다.

RBAC (역할 기반 접근 제어)

가장 보편적인 인가 모델입니다. 사용자에게 역할을 부여하고, 역할에 권한을 매핑합니다.

RBAC 구현 예시

PERMISSIONS = {

"admin": ["read", "write", "delete", "manage_users"],

"editor": ["read", "write"],

"viewer": ["read"],

}

def check_permission(user_role, required_permission):

role_permissions = PERMISSIONS.get(user_role, [])

return required_permission in role_permissions

사용

if check_permission(current_user.role, "delete"):

delete_resource(resource_id)

else:

raise PermissionError("삭제 권한이 없습니다")

ABAC (속성 기반 접근 제어)

사용자 속성, 리소스 속성, 환경 속성을 기반으로 세밀한 접근 제어를 수행합니다.

ABAC 정책 예시

def evaluate_policy(user, resource, action, environment):

근무 시간에만 접근 허용

if environment["hour"] < 9 or environment["hour"] > 18:

return False

같은 부서의 문서만 접근 가능

if user["department"] != resource["department"]:

return False

매니저는 모든 작업 가능, 일반 직원은 읽기만

if action == "write" and user["level"] < 3:

return False

return True

OAuth 2.0 스코프

OAuth 2.0에서 스코프는 클라이언트가 접근할 수 있는 리소스의 범위를 제한합니다.

OAuth 2.0 스코프 정의 예시

scopes:

read:profile: "사용자 프로필 읽기"

write:profile: "사용자 프로필 수정"

read:orders: "주문 내역 조회"

admin:users: "사용자 관리 (관리자 전용)"

JWT 보안 모범 사례

JWT는 편리하지만, 잘못 사용하면 심각한 보안 문제가 발생합니다.

from datetime import datetime, timedelta, timezone

JWT 생성 (RS256 권장)

def create_token(user_id, role):

payload = {

"sub": user_id,

"role": role,

"iat": datetime.now(timezone.utc),

"exp": datetime.now(timezone.utc) + timedelta(minutes=15),

"iss": "myapp.com",

"aud": "myapp.com"

}

return jwt.encode(payload, PRIVATE_KEY, algorithm="RS256")

JWT 검증

def verify_token(token):

try:

payload = jwt.decode(

token,

PUBLIC_KEY,

algorithms=["RS256"], # 알고리즘 명시적 지정 (none 공격 방지)

issuer="myapp.com",

audience="myapp.com"

)

return payload

except jwt.ExpiredSignatureError:

raise AuthError("토큰이 만료되었습니다")

except jwt.InvalidTokenError:

raise AuthError("유효하지 않은 토큰입니다")

**JWT 보안 체크리스트**:

- HS256 대신 RS256 사용 (비대칭 서명)

- 만료 시간(exp)을 짧게 설정 (15분 이내)

- Refresh Token은 서버 사이드에서 관리

- alg: none 공격을 방지하기 위해 알고리즘을 명시적으로 검증

5. 암호화 실전

대칭 암호화: AES-256-GCM

동일한 키로 암호화와 복호화를 수행합니다. 데이터 저장 시 주로 사용됩니다.

from cryptography.hazmat.primitives.ciphers.aead import AESGCM

키 생성 (256비트)

key = AESGCM.generate_key(bit_length=256)

암호화

aesgcm = AESGCM(key)

nonce = os.urandom(12) # 96비트 논스

plaintext = b"Sensitive data here"

aad = b"additional authenticated data" # 추가 인증 데이터

ciphertext = aesgcm.encrypt(nonce, plaintext, aad)

복호화

decrypted = aesgcm.decrypt(nonce, ciphertext, aad)

비대칭 암호화: RSA와 ECDSA

from cryptography.hazmat.primitives.asymmetric import ec

from cryptography.hazmat.primitives import hashes, serialization

ECDSA 키 쌍 생성

private_key = ec.generate_private_key(ec.SECP256R1())

public_key = private_key.public_key()

서명

from cryptography.hazmat.primitives.asymmetric import utils

signature = private_key.sign(

b"message to sign",

ec.ECDSA(hashes.SHA256())

)

검증

public_key.verify(

signature,

b"message to sign",

ec.ECDSA(hashes.SHA256())

)

TLS 설정 모범 사례

Nginx TLS 설정

server {

listen 443 ssl http2;

ssl_protocols TLSv1.2 TLSv1.3;

ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;

ssl_prefer_server_ciphers on;

HSTS 헤더

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

OCSP Stapling

ssl_stapling on;

ssl_stapling_verify on;

}

키 관리와 HSM

- 키를 소스 코드에 하드코딩하면 안 됩니다

- AWS KMS, Google Cloud KMS, Azure Key Vault 같은 관리형 서비스를 사용합니다

- HSM(Hardware Security Module)은 키를 하드웨어 내부에서만 처리하여 추출을 방지합니다

- 키 로테이션 정책을 수립하고 자동화합니다

6. 시큐어 코딩

입력 검증

모든 외부 입력은 신뢰할 수 없습니다.

from pydantic import BaseModel, validator, constr

class UserInput(BaseModel):

username: constr(min_length=3, max_length=30, pattern=r'^[a-zA-Z0-9_]+$')

email: str

age: int

@validator('email')

def validate_email(cls, v):

pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'

if not re.match(pattern, v):

raise ValueError('유효하지 않은 이메일 형식입니다')

return v

@validator('age')

def validate_age(cls, v):

if v < 0 or v > 150:

raise ValueError('유효하지 않은 나이입니다')

return v

출력 인코딩 (XSS 방지)

HTML 출력 시 이스케이프

from markupsafe import escape

user_input = '<script>alert("XSS")</script>'

safe_output = escape(user_input)

결과: &lt;script&gt;alert("XSS")&lt;/script&gt;

파라미터화 쿼리

SQLAlchemy ORM 사용

from sqlalchemy import text

안전한 방법

result = db.session.execute(

text("SELECT * FROM users WHERE email = :email"),

{"email": user_email}

)

CORS 설정

Flask-CORS 설정

from flask_cors import CORS

CORS(app, resources={

r"/api/*": {

"origins": ["https://myapp.com", "https://admin.myapp.com"],

"methods": ["GET", "POST", "PUT", "DELETE"],

"allow_headers": ["Content-Type", "Authorization"],

"max_age": 86400

}

})

CSP (Content Security Policy)

CSP 헤더 설정

@app.after_request

def set_csp(response):

response.headers['Content-Security-Policy'] = (

"default-src 'self'; "

"script-src 'self' 'nonce-abc123'; "

"style-src 'self' 'unsafe-inline'; "

"img-src 'self' data: https:; "

"connect-src 'self' https://api.myapp.com; "

"frame-ancestors 'none'; "

"base-uri 'self'"

)

return response

7. API 보안

Rate Limiting

Flask-Limiter 사용

from flask_limiter import Limiter

limiter = Limiter(

app,

default_limits=["200 per day", "50 per hour"]

)

@app.route("/api/login", methods=["POST"])

@limiter.limit("5 per minute")

def login():

로그인 로직

pass

@app.route("/api/data")

@limiter.limit("100 per hour")

def get_data():

데이터 조회 로직

pass

API Key 관리

- API Key는 헤더로 전달합니다 (URL 파라미터에 넣지 않습니다)

- 키별 권한 범위(scope)를 제한합니다

- 키 발급/폐기 이력을 관리합니다

- 사용량을 모니터링하고 이상 패턴을 감지합니다

mTLS (상호 TLS 인증)

서버와 클라이언트 양쪽 모두 인증서를 검증하는 방식입니다.

Kubernetes Ingress에서 mTLS 설정 예시

apiVersion: networking.k8s.io/v1

kind: Ingress

metadata:

annotations:

nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"

nginx.ingress.kubernetes.io/auth-tls-secret: "default/ca-secret"

spec:

tls:

- hosts:

- api.myapp.com

secretName: tls-secret

HMAC 서명

요청의 무결성과 인증을 동시에 보장합니다.

def create_hmac_signature(secret_key, method, path, body, timestamp):

message = f"{method}\n{path}\n{timestamp}\n{body}"

signature = hmac.new(

secret_key.encode(),

message.encode(),

hashlib.sha256

).hexdigest()

return signature

검증 (타임스탬프 체크 포함)

def verify_request(secret_key, method, path, body, timestamp, signature):

5분 이내의 요청만 허용 (Replay 공격 방지)

if abs(time.time() - float(timestamp)) > 300:

return False

expected = create_hmac_signature(secret_key, method, path, body, timestamp)

return hmac.compare_digest(expected, signature)

8. 컨테이너 보안

이미지 스캔

Trivy로 컨테이너 이미지 취약점 스캔

trivy image myapp:latest

심각도별 필터링

trivy image --severity HIGH,CRITICAL myapp:latest

CI/CD에서 사용 (취약점 발견 시 빌드 실패)

trivy image --exit-code 1 --severity CRITICAL myapp:latest

최소 권한 Dockerfile

멀티 스테이지 빌드

FROM node:20-alpine AS builder

WORKDIR /app

COPY package*.json ./

RUN npm ci --only=production

COPY . .

RUN npm run build

프로덕션 이미지

FROM node:20-alpine

RUN addgroup -g 1001 -S appgroup && \

adduser -S appuser -u 1001 -G appgroup

WORKDIR /app

COPY --from=builder --chown=appuser:appgroup /app/dist ./dist

COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules

루트가 아닌 사용자로 실행

USER appuser

EXPOSE 3000

CMD ["node", "dist/server.js"]

Rootless 컨테이너

- 루트 권한 없이 컨테이너를 실행합니다

- securityContext에서 runAsNonRoot, readOnlyRootFilesystem을 설정합니다

- 불필요한 Linux Capabilities를 제거합니다

Kubernetes Pod Security Context

apiVersion: v1

kind: Pod

metadata:

name: secure-app

spec:

securityContext:

runAsNonRoot: true

runAsUser: 1001

fsGroup: 1001

containers:

- name: app

image: myapp:latest

securityContext:

allowPrivilegeEscalation: false

readOnlyRootFilesystem: true

capabilities:

drop:

- ALL

OPA/Gatekeeper

Kubernetes 클러스터의 정책을 코드로 관리합니다.

특권 컨테이너 차단 정책

apiVersion: constraints.gatekeeper.sh/v1beta1

kind: K8sPSPPrivilegedContainer

metadata:

name: deny-privileged

spec:

match:

kinds:

- apiGroups: [""]

kinds: ["Pod"]

excludedNamespaces:

- kube-system

9. DevSecOps 파이프라인

전체 파이프라인 개요

DevSecOps는 개발(Dev), 보안(Sec), 운영(Ops)을 통합하는 접근법입니다.

| 단계 | 도구 | 목적 |

| --- | --- | --- |

| 코드 작성 | IDE 보안 플러그인 | 실시간 취약점 감지 |

| 커밋 | Pre-commit hooks | 비밀키 유출 방지 |

| 빌드 | SAST | 정적 코드 분석 |

| 테스트 | DAST | 동적 보안 테스트 |

| 의존성 | SCA | 서드파티 라이브러리 취약점 |

| 배포 | 이미지 스캔 | 컨테이너 취약점 |

| 운영 | RASP, WAF | 런타임 보안 |

SAST (Static Application Security Testing)

GitHub Actions에서 SonarQube 실행

name: Security Scan

on: [push, pull_request]

jobs:

sonarqube:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: SonarQube Scan

uses: sonarsource/sonarqube-scan-action@master

env:

SONAR_TOKEN: SONAR_TOKEN_PLACEHOLDER

SONAR_HOST_URL: SONAR_HOST_PLACEHOLDER

DAST (Dynamic Application Security Testing)

OWASP ZAP을 사용한 동적 보안 스캔

docker run -t zaproxy/zap-stable zap-baseline.py \

-t https://myapp.com \

-r report.html

SCA (Software Composition Analysis)

Dependabot 설정 (.github/dependabot.yml)

version: 2

updates:

- package-ecosystem: "npm"

directory: "/"

schedule:

interval: "weekly"

open-pull-requests-limit: 10

- package-ecosystem: "pip"

directory: "/"

schedule:

interval: "weekly"

SBOM (Software Bill of Materials)

Syft로 SBOM 생성

syft myapp:latest -o spdx-json > sbom.json

Grype로 SBOM 기반 취약점 스캔

grype sbom:sbom.json

Pre-commit에서 비밀키 감지

.pre-commit-config.yaml

repos:

- repo: https://github.com/Yelp/detect-secrets

rev: v1.4.0

hooks:

- id: detect-secrets

args: ['--baseline', '.secrets.baseline']

- repo: https://github.com/zricethezav/gitleaks

rev: v8.18.0

hooks:

- id: gitleaks

10. 침투 테스트 기초

모의해킹 방법론

**OWASP Testing Guide** 기반의 테스트 단계:

1. **정보 수집 (Reconnaissance)**: 대상 시스템의 기술 스택, 네트워크 구조 파악

2. **매핑 (Mapping)**: 공격 표면(Attack Surface) 식별

3. **취약점 발견 (Discovery)**: 자동화 도구와 수동 테스트 병행

4. **취약점 검증 (Exploitation)**: 발견된 취약점의 실제 위험도 검증

5. **보고 (Reporting)**: 기술적 상세 내용과 비즈니스 영향도 보고

유용한 도구들

| 도구 | 용도 |

| --- | --- |

| Burp Suite | 웹 프록시, 취약점 스캐너 |

| Nmap | 네트워크 스캔 |

| sqlmap | SQL Injection 자동화 |

| Nuclei | 템플릿 기반 취약점 스캔 |

| Metasploit | 침투 테스트 프레임워크 |

버그 바운티 프로그램

자사 서비스의 취약점을 외부 보안 연구자가 발견하도록 보상하는 프로그램입니다.

- **HackerOne**: 세계 최대의 버그 바운티 플랫폼

- **Bugcrowd**: 크라우드소싱 보안 테스트

- **자체 운영**: 명확한 범위(scope)와 보상 기준 설정이 중요합니다

CTF (Capture The Flag) 추천

보안 실력을 키울 수 있는 CTF 플랫폼입니다.

- **OverTheWire**: 기초부터 고급까지 단계별 워게임

- **Hack The Box**: 실전형 침투 테스트 환경

- **PicoCTF**: 초보자에게 적합한 교육용 CTF

- **PortSwigger Web Security Academy**: 웹 보안 무료 학습 플랫폼

11. 인시던트 대응

보안 사고 대응 절차 (NIST SP 800-61)

**1단계: 준비 (Preparation)**

- 인시던트 대응 팀(IRT) 구성

- 대응 계획 수립 및 훈련

- 연락 체계와 에스컬레이션 절차 정의

**2단계: 탐지 및 분석 (Detection and Analysis)**

- SIEM(Security Information and Event Management)으로 이상 탐지

- 로그 분석 및 IoC(Indicators of Compromise) 식별

- 사고의 범위와 영향도 파악

**3단계: 억제, 근절, 복구 (Containment, Eradication, Recovery)**

비상 대응 예시: 유출된 API 키 무효화

1. 영향받은 키 즉시 폐기

aws iam delete-access-key --user-name compromised-user --access-key-id AKIA...

2. 관련 세션 모두 무효화

aws iam put-user-policy --user-name compromised-user \

--policy-name DenyAll --policy-document file://deny-all.json

3. 새 인증 정보 발급 후 안전하게 배포

**4단계: 사후 활동 (Post-Incident Activity)**

- 사후 보고서(Post-mortem) 작성

- 타임라인 재구성

- 근본 원인 분석 (Root Cause Analysis)

- 재발 방지 대책 수립 및 이행

디지털 포렌식 기초

- 증거 보전의 원칙: 원본을 훼손하지 않고 사본으로 분석합니다

- Chain of Custody: 증거의 취급 이력을 문서화합니다

- 메모리 덤프, 디스크 이미징, 네트워크 트래픽 캡처 등 수집 방법을 이해합니다

- 주요 도구: Volatility (메모리 분석), Autopsy (디스크 분석), Wireshark (네트워크 분석)

보안 사고 보고서 구조

좋은 보안 사고 보고서는 다음 항목을 포함합니다.

1. **사고 개요**: 발생 일시, 유형, 영향 범위

2. **타임라인**: 최초 침투부터 발견까지의 시간순 기록

3. **기술적 분석**: 공격 벡터, 악용된 취약점, 공격자의 행위

4. **영향 분석**: 유출된 데이터의 종류와 규모, 비즈니스 영향

5. **대응 조치**: 취한 조치와 효과

6. **재발 방지**: 단기/장기 개선 사항

7. **교훈**: 대응 과정에서의 개선점

마무리

애플리케이션 보안은 단일 도구나 프로세스가 아닌, 문화이자 여정입니다. 핵심 원칙을 정리합니다.

1. **심층 방어 (Defense in Depth)**: 하나의 보안 계층이 실패해도 다른 계층이 방어합니다

2. **최소 권한 (Least Privilege)**: 필요한 최소한의 권한만 부여합니다

3. **실패 안전 (Fail Secure)**: 시스템 오류 시 보안이 유지되는 방향으로 설계합니다

4. **제로 트러스트 (Zero Trust)**: 네트워크 위치에 관계없이 모든 요청을 검증합니다

5. **보안은 문화**: 모든 팀원이 보안 의식을 가지고, 지속적으로 학습합니다

보안 위협은 끊임없이 진화합니다. 이 가이드를 출발점으로 삼아 지속적인 학습과 실무 적용을 병행하시기 바랍니다.

**Q1.** OWASP Top 10 (2021)에서 1위를 차지한 취약점은 무엇인가요?

A: Broken Access Control (접근 제어 실패). 인가되지 않은 사용자가 다른 사용자의 데이터에 접근하거나 관리자 기능을 수행할 수 있는 취약점입니다.

**Q2.** 비밀번호 해싱에 MD5를 사용하면 안 되는 이유는?

A: MD5는 속도가 너무 빠르기 때문에 무차별 대입 공격(Brute-force)에 취약합니다. bcrypt나 Argon2처럼 의도적으로 느리게 설계된 알고리즘을 사용해야 합니다.

**Q3.** JWT에서 alg: none 공격을 방지하려면 어떻게 해야 하나요?

A: 토큰 검증 시 허용할 알고리즘을 명시적으로 지정해야 합니다. 라이브러리의 기본 설정에 의존하지 않고 algorithms=["RS256"]처럼 구체적으로 지정합니다.

**Q4.** SAST와 DAST의 차이점은 무엇인가요?

A: SAST(Static)는 소스 코드를 실행 없이 분석하여 취약점을 찾고, DAST(Dynamic)는 실행 중인 애플리케이션을 대상으로 외부에서 공격을 시뮬레이션합니다. 둘 다 상호 보완적으로 사용해야 합니다.

**Q5.** SSRF 공격을 방어하는 가장 효과적인 방법은?

A: 허용된 URL의 화이트리스트를 적용하고, 내부 네트워크 IP 대역(10.x, 172.16.x, 192.168.x, 127.0.0.1)으로의 요청을 차단합니다. DNS Rebinding 공격도 함께 방어해야 합니다.

현재 단락 (1/503)

소프트웨어가 비즈니스의 핵심이 된 시대, 보안은 선택이 아니라 생존의 문제입니다. 이 가이드는 OWASP Top 10부터 DevSecOps 파이프라인까지 애플리케이션 보안의 전 범...

작성 글자: 0원문 글자: 15,824작성 단락: 0/503