Skip to content
Published on

Wireshark와 네트워크 보안 완전 가이드: 패킷 스니핑부터 침투 탐지까지 개발자를 위한 실전 보안

Authors

1. 왜 개발자에게 네트워크 보안이 중요한가

보안은 선택이 아니라 필수다

2025년 IBM의 Cost of a Data Breach Report에 따르면, 데이터 유출 사고의 평균 비용은 488만 달러에 달합니다. 이는 전년 대비 10% 상승한 수치이며, 사상 최고치입니다. 더 충격적인 것은 보안 사고의 60% 이상이 애플리케이션 레이어에서 발생한다는 점입니다.

OWASP Top 10 2025를 보면 개발자가 직접 관여해야 하는 취약점이 대부분입니다:

순위취약점개발자 관련도
1Broken Access Control매우 높음
2Cryptographic Failures높음
3Injection (SQL, XSS, LDAP)매우 높음
4Insecure Design매우 높음
5Security Misconfiguration높음
6Vulnerable Components높음
7Authentication Failures매우 높음
8Data Integrity Failures높음
9Logging/Monitoring Failures보통
10SSRF (Server-Side Request Forgery)매우 높음

2026년 사이버 위협 환경

2026년은 사이버 보안 역사에서 가장 위험한 해로 기록되고 있습니다. 미국-이란 갈등이 고조되면서 국가 지원 해킹 그룹의 활동이 700% 이상 증가했습니다. 특히:

  • APT 그룹 활동 급증: 국가 지원 해킹 그룹이 금융, 에너지, 의료 인프라를 집중 공격
  • 공급망 공격 확대: npm, PyPI 등 패키지 저장소를 통한 악성코드 배포가 3배 증가
  • AI 기반 공격: LLM을 활용한 피싱 메일, 자동화된 취약점 스캐닝이 일상화
  • 랜섬웨어 진화: 이중 갈취(데이터 유출 + 암호화) 전략이 표준화

DevSecOps와 Shift-Left 보안

전통적인 보안은 개발이 끝난 후 테스트 단계에서 수행했습니다. 하지만 Shift-Left 접근법은 개발 초기 단계부터 보안을 통합합니다.

전통적 접근:
  설계 → 개발 → 테스트 → [보안 테스트] → 배포
  ← 문제 발견 시 비용이 기하급수적으로 증가 →

Shift-Left:
  [보안 설계][보안 코딩][보안 테스트][보안 모니터링]
  ← 조기 발견으로 비용 절감 →

개발자가 네트워크 패킷을 읽을 수 있다면:

  • API 호출에서 민감한 데이터가 평문으로 전송되는지 직접 확인 가능
  • TLS 설정 오류를 배포 전에 발견 가능
  • 서드파티 라이브러리의 수상한 네트워크 활동 탐지 가능
  • 성능 병목과 보안 취약점을 동시에 진단 가능

2. Wireshark 완전 정복

2-1. 설치 및 초기 설정

macOS:

brew install --cask wireshark

Ubuntu/Debian:

sudo apt update
sudo apt install wireshark
sudo usermod -aG wireshark $USER
# 로그아웃 후 재로그인 필요

Windows:

공식 사이트(wireshark.org)에서 설치 파일을 다운로드합니다. 설치 시 Npcap을 함께 설치해야 합니다.

2-2. 인터페이스 구성

Wireshark의 메인 화면은 3개 패널로 구성됩니다:

  1. 패킷 리스트 패널 (상단): 캡처된 모든 패킷의 요약 정보
  2. 패킷 디테일 패널 (중단): 선택한 패킷의 프로토콜 계층별 상세 정보
  3. 패킷 바이트 패널 (하단): 원시 바이너리 데이터 (Hex + ASCII)

2-3. Capture Filters vs Display Filters

이 두 필터는 Wireshark를 효과적으로 사용하기 위한 핵심입니다. 가장 중요한 차이는 적용 시점입니다.

구분Capture FilterDisplay Filter
적용 시점캡처 시작 전캡처 후 (실시간 변경 가능)
문법BPF (Berkeley Packet Filter)Wireshark 자체 문법
성능높음 (커널 레벨 필터링)낮음 (모든 패킷 캡처 후 필터링)
유연성제한적매우 유연
예시host 192.168.1.1ip.addr == 192.168.1.1
예시port 80tcp.port == 80
예시tcp and port 443tcp.port == 443

Capture Filter 예시:

host 10.0.0.1
port 443
net 192.168.0.0/24
tcp and port 80
not arp

Display Filter 예시:

ip.addr == 10.0.0.1
tcp.port == 443
http.request.method == "GET"
dns.qry.name contains "google"

2-4. 필수 Display Filters 30선

번호필터용도
1ip.addr == 10.0.0.1특정 IP 필터링
2tcp.port == 443HTTPS 트래픽
3tcp.port == 80HTTP 트래픽
4http.request.method == "POST"POST 요청만
5http.request.method == "GET"GET 요청만
6dns.qry.name contains "example"특정 도메인 DNS 쿼리
7tcp.flags.syn == 1 and tcp.flags.ack == 0SYN 스캔 탐지
8tcp.analysis.retransmissionTCP 재전송 탐지
9tcp.analysis.duplicate-ack중복 ACK 탐지
10tcp.analysis.zero-windowZero Window 탐지
11http.response.code == 500서버 에러 응답
12http.response.code >= 400모든 에러 응답
13tls.handshake.type == 1TLS Client Hello
14tls.handshake.type == 2TLS Server Hello
15arpARP 패킷만
16icmpICMP (ping) 패킷만
17dnsDNS 패킷만
18tcp.analysis.flagsTCP 문제가 있는 패킷
19http.cookie contains "session"세션 쿠키 포함 요청
20frame.time_delta > 11초 이상 지연된 패킷
21tcp.len > 0데이터가 있는 TCP 패킷
22ip.src == 10.0.0.0/8내부 네트워크 소스
23not arp and not dnsARP, DNS 제외
24http.host contains "api"API 호출 필터링
25tcp.stream eq 5특정 TCP 스트림
26frame.len > 1500MTU 초과 패킷
27http.content_type contains "json"JSON 응답
28tcp.analysis.lost_segment손실 세그먼트
29ip.ttl < 10낮은 TTL (라우팅 문제)
30tls.handshake.extensions_server_nameSNI 기반 필터링

2-5. Follow Stream 기능

TCP Stream 추적은 Wireshark의 가장 강력한 기능 중 하나입니다:

  1. 패킷을 우클릭합니다
  2. Follow > TCP Stream 선택
  3. 해당 연결의 전체 데이터 흐름을 볼 수 있습니다
# TCP Stream 예시 (HTTP 요청/응답)
GET /api/users HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json
Set-Cookie: session=abc123; HttpOnly; Secure

[Response Body]

HTTP Stream은 HTTP/2 멀티플렉싱 환경에서 개별 HTTP 트랜잭션을 추적할 때 유용합니다.

2-6. Statistics 메뉴 활용

Conversations: 어떤 IP 간에 가장 많은 트래픽이 오가는지 확인

Source          Destination     Packets   Bytes
10.0.0.5        52.85.132.99    1,234     890KB
10.0.0.5        142.250.80.46   567       234KB
10.0.0.5        104.18.32.68    345       156KB

Protocol Hierarchy: 프로토콜별 트래픽 비율 확인

Ethernet (100%)
  ├── IPv4 (98.5%)
  │   ├── TCP (85.2%)
  │   │   ├── TLS (62.1%)
  │   │   ├── HTTP (15.3%)
  │   │   └── Other (7.8%)
  │   ├── UDP (12.8%)
  │   │   ├── DNS (8.2%)
  │   │   └── QUIC (4.6%)
  │   └── ICMP (0.5%)
  └── ARP (1.5%)

I/O Graphs: 시간대별 트래픽 패턴을 시각화합니다. DDoS 공격이나 트래픽 스파이크를 탐지하는 데 필수적입니다.

2-7. 프로파일 설정과 컬럼 커스텀

프로파일을 만들면 용도별로 최적화된 환경을 전환할 수 있습니다:

프로파일 예시:
  - Default: 일반 분석
  - Security: 보안 분석 (색상 규칙, 보안 관련 컬럼)
  - Performance: 성능 분석 (지연시간, 재전송 컬럼)
  - DNS: DNS 분석 전용

유용한 커스텀 컬럼:

  • Delta Time: 이전 패킷과의 시간 차이
  • TCP Stream Index: 스트림 번호
  • HTTP Host: HTTP 요청의 호스트 헤더
  • TLS SNI: TLS Server Name Indication

3. tcpdump 실전 (서버 환경)

3-1. 기본 문법과 BPF 필터

tcpdump는 서버에서 GUI 없이 패킷을 캡처하는 도구입니다. Wireshark와 동일한 BPF(Berkeley Packet Filter) 문법을 사용합니다.

기본 구조:

tcpdump [옵션] [BPF 필터 표현식]

주요 옵션:

-i eth0        # 인터페이스 지정
-w output.pcap # 파일로 저장
-r input.pcap  # 파일 읽기
-c 100         # 패킷 100개만 캡처
-n             # DNS 역조회 비활성화 (속도 향상)
-nn            # 포트 번호도 이름 변환 안 함
-v / -vv / -vvv  # 상세도 증가
-X             # Hex + ASCII 출력
-A             # ASCII만 출력
-s 0           # 전체 패킷 캡처 (기본: 262144 bytes)
-tttt          # 타임스탬프를 읽기 쉬운 형식으로

3-2. 실전 명령어 20개

번호명령어용도
1sudo tcpdump -i eth0기본 캡처
2sudo tcpdump -i eth0 -w capture.pcap파일로 저장
3sudo tcpdump -i eth0 host 10.0.0.1특정 호스트
4sudo tcpdump -i eth0 port 443특정 포트
5sudo tcpdump -i eth0 src 10.0.0.1소스 IP 필터
6sudo tcpdump -i eth0 dst port 80목적지 포트 필터
7sudo tcpdump -i eth0 net 192.168.0.0/24서브넷 필터
8sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0'SYN 패킷만
9sudo tcpdump -i eth0 -c 1000 -w sample.pcap1000개만 캡처
10sudo tcpdump -i eth0 -nn port 53DNS 트래픽
11sudo tcpdump -i eth0 icmpICMP(ping)만
12sudo tcpdump -i eth0 'port 80 and host 10.0.0.1'복합 필터
13sudo tcpdump -i eth0 -A port 80HTTP 내용 보기
14sudo tcpdump -i eth0 'tcp[32:4] = 0x47455420'GET 요청만
15sudo tcpdump -i eth0 greater 10001000바이트 초과
16sudo tcpdump -i eth0 arpARP 패킷만
17sudo tcpdump -i eth0 -tttt -c 50 port 443타임스탬프 포함
18sudo tcpdump -i any port 8080모든 인터페이스
19sudo tcpdump -i eth0 not port 22SSH 제외
20sudo tcpdump -i eth0 -G 3600 -w 'capture_%Y%m%d_%H.pcap'시간별 로테이션

3-3. 원격 서버 캡처 후 Wireshark 분석

서버에서 캡처한 pcap 파일을 로컬로 가져와 Wireshark에서 분석하는 워크플로우:

# 1. 서버에서 캡처
ssh user@server 'sudo tcpdump -i eth0 -c 5000 -w /tmp/capture.pcap port 443'

# 2. 로컬로 복사
scp user@server:/tmp/capture.pcap ./analysis/

# 3. Wireshark로 열기
wireshark ./analysis/capture.pcap

3-4. tcpdump + ssh 파이프라인 (실시간)

원격 서버의 패킷을 실시간으로 로컬 Wireshark에서 분석:

# 방법 1: ssh 파이프
ssh user@server 'sudo tcpdump -i eth0 -w - port 443' | wireshark -k -i -

# 방법 2: named pipe 사용
mkfifo /tmp/remote_capture
wireshark -k -i /tmp/remote_capture &
ssh user@server 'sudo tcpdump -i eth0 -w - port 443' > /tmp/remote_capture

# 방법 3: 특정 기간만 캡처
ssh user@server 'sudo timeout 60 tcpdump -i eth0 -w - port 80' | wireshark -k -i -

이 기법은 프로덕션 서버에서 발생하는 네트워크 이슈를 실시간으로 분석할 때 매우 유용합니다.


4. 패킷으로 읽는 프로토콜 분석

4-1. TCP 3-Way Handshake 패킷 분석

TCP 연결 설정의 3-Way Handshake를 패킷 레벨에서 분석합니다:

Step 1: SYN (클라이언트 → 서버)
  Source: 10.0.0.5:54321
  Dest:   93.184.216.34:443
  Flags:  [SYN]
  Seq:    0 (ISN: Initial Sequence Number)
  Win:    65535
  Options: MSS=1460, SACK Permitted, Window Scale=6

Step 2: SYN-ACK (서버 → 클라이언트)
  Source: 93.184.216.34:443
  Dest:   10.0.0.5:54321
  Flags:  [SYN, ACK]
  Seq:    0 (서버의 ISN)
  Ack:    1 (클라이언트 ISN + 1)
  Win:    65535
  Options: MSS=1400, SACK Permitted, Window Scale=7

Step 3: ACK (클라이언트 → 서버)
  Source: 10.0.0.5:54321
  Dest:   93.184.216.34:443
  Flags:  [ACK]
  Seq:    1
  Ack:    1
  Win:    65535

Wireshark 필터: tcp.flags.syn == 1 으로 SYN 패킷을 찾고, Follow TCP Stream으로 전체 핸드셰이크를 확인합니다.

문제 진단 포인트:

  • SYN만 있고 SYN-ACK가 없으면: 서버가 응답하지 않음 (방화벽 차단 가능)
  • SYN-ACK는 오지만 최종 ACK가 없으면: 클라이언트 측 문제
  • RST 패킷이 즉시 오면: 포트가 닫혀 있거나 방화벽이 연결 거부

4-2. HTTP 요청/응답 분석

# HTTP 요청 패킷 상세
Frame 45: 342 bytes on wire
  Ethernet II: Src=aa:bb:cc:dd:ee:ff, Dst=11:22:33:44:55:66
  Internet Protocol Version 4: Src=10.0.0.5, Dst=93.184.216.34
  Transmission Control Protocol: Src Port=54321, Dst Port=80
  Hypertext Transfer Protocol:
    GET /api/v1/users?page=1 HTTP/1.1
    Host: api.example.com
    User-Agent: Mozilla/5.0 ...
    Accept: application/json
    Authorization: Bearer eyJhbGci...
    Cookie: session_id=abc123
    Connection: keep-alive

# HTTP 응답 패킷 상세
Frame 47: 1280 bytes on wire
  Hypertext Transfer Protocol:
    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    Content-Length: 956
    Set-Cookie: session_id=xyz789; HttpOnly; Secure; SameSite=Strict
    X-Request-Id: req_abc123
    Strict-Transport-Security: max-age=31536000
    X-Content-Type-Options: nosniff

보안 관점에서 확인할 사항:

  • Authorization 헤더가 평문 HTTP로 전송되고 있지 않은지
  • Set-Cookie에 HttpOnly, Secure 플래그가 있는지
  • 보안 헤더(HSTS, X-Content-Type-Options 등)가 설정되어 있는지
  • 응답에 민감한 정보가 포함되어 있지 않은지

4-3. DNS 질의/응답 패킷 구조

# DNS 질의 (Query)
Domain Name System (query)
  Transaction ID: 0x1a2b
  Flags: 0x0100 Standard query
  Questions: 1
  Queries:
    api.example.com: type A, class IN

# DNS 응답 (Response)
Domain Name System (response)
  Transaction ID: 0x1a2b
  Flags: 0x8180 Standard query response, No error
  Questions: 1
  Answer RRs: 2
  Answers:
    api.example.com: type A, class IN, addr 93.184.216.34
      TTL: 300 (5 minutes)
    api.example.com: type A, class IN, addr 93.184.216.35
      TTL: 300 (5 minutes)

DNS 보안 점검:

  • DNS 쿼리가 암호화되지 않은 채로 전송되고 있는지 (DoH/DoT 사용 여부)
  • 비정상적으로 긴 도메인 이름 (DNS tunneling 의심)
  • 알 수 없는 DNS 서버로의 쿼리 (DNS hijacking 가능성)

4-4. TLS Handshake 패킷 분석

TLS 1.3 핸드셰이크는 1-RTT(Round Trip Time)로 이전 버전보다 빠릅니다:

Step 1: Client Hello
  TLS Record Layer:
    Content Type: Handshake (22)
    Version: TLS 1.0 (호환성)
  Handshake Protocol: Client Hello
    Version: TLS 1.2 (호환성을 위해)
    Random: [32 bytes]
    Session ID: [32 bytes]
    Cipher Suites (17 suites):
      TLS_AES_256_GCM_SHA384
      TLS_AES_128_GCM_SHA256
      TLS_CHACHA20_POLY1305_SHA256
    Extensions:
      server_name: api.example.com  (SNI)
      supported_versions: TLS 1.3
      key_share: x25519 [public key]
      signature_algorithms: ecdsa_secp256r1_sha256, rsa_pss_rsae_sha256

Step 2: Server Hello + Certificate + Finished
  Handshake Protocol: Server Hello
    Cipher Suite: TLS_AES_256_GCM_SHA384
    Key Share: x25519 [server public key]
  [Encrypted Extensions]
  [Certificate]
  [Certificate Verify]
  [Finished]

Step 3: Client Finished (Encrypted)
  [Change Cipher Spec]
  [Finished]

4-5. TLS 복호화: SSLKEYLOGFILE 환경변수 설정

개발/디버깅 환경에서 TLS 트래픽을 복호화할 수 있습니다:

# 1. 환경변수 설정 (bash)
export SSLKEYLOGFILE="$HOME/.ssl-keys.log"

# 2. Chrome 또는 Firefox 실행 (이 환경변수를 자동으로 인식)
# 브라우저가 TLS 세션 키를 파일에 기록합니다

# 3. curl에서도 사용 가능
SSLKEYLOGFILE=$HOME/.ssl-keys.log curl https://api.example.com/health

Wireshark 설정:

  1. Edit > Preferences > Protocols > TLS
  2. (Pre)-Master-Secret log filename에 키 파일 경로 입력
  3. 이후 캡처된 TLS 트래픽이 복호화되어 표시됩니다

주의: 프로덕션 환경에서는 절대 사용하지 마세요. 개발/스테이징 환경에서만 사용하세요.


5. 공격 탐지 실전

5-1. ARP Spoofing 탐지

ARP Spoofing은 로컬 네트워크에서 MAC 주소를 위조하여 트래픽을 가로채는 공격입니다.

정상 ARP 동작:

Who has 10.0.0.1? Tell 10.0.0.5
10.0.0.1 is at aa:bb:cc:dd:ee:ff

ARP Spoofing 탐지 시나리오:

# 공격자가 게이트웨이(10.0.0.1)를 사칭
10.0.0.1 is at [공격자 MAC: 11:22:33:44:55:66]  ← 비정상!
10.0.0.1 is at [실제 MAC: aa:bb:cc:dd:ee:ff]     ← 정상

# 같은 IP에 대해 두 개의 다른 MAC 주소 → ARP Spoofing!

Wireshark 필터:

arp.duplicate-address-detected
arp.duplicate-address-frame

탐지 스크립트:

#!/bin/bash
# ARP 테이블 모니터링
while true; do
    arp -a | sort > /tmp/arp_current.txt
    if [ -f /tmp/arp_previous.txt ]; then
        diff /tmp/arp_previous.txt /tmp/arp_current.txt
        if [ $? -ne 0 ]; then
            echo "[ALERT] ARP table changed at $(date)"
            diff /tmp/arp_previous.txt /tmp/arp_current.txt
        fi
    fi
    cp /tmp/arp_current.txt /tmp/arp_previous.txt
    sleep 10
done

5-2. Port Scanning 탐지

SYN Scan (Half-Open Scan) 패턴:

Nmap의 기본 스캔 방식입니다. SYN 패킷만 보내고 연결을 완료하지 않습니다.

공격자 → 대상:22  [SYN]
대상:22 → 공격자  [SYN,ACK]  ← 포트 열림
공격자 → 대상:22  [RST]       ← 연결 완료 안 함

공격자 → 대상:23  [SYN]
대상:23 → 공격자  [RST,ACK]  ← 포트 닫힘

Wireshark 필터:

# SYN 스캔 탐지 (ACK 없는 SYN)
tcp.flags.syn == 1 and tcp.flags.ack == 0

# 짧은 시간에 다수의 포트로 SYN
tcp.flags.syn == 1 and tcp.flags.ack == 0 and ip.src == 10.0.0.100

Nmap 스캔 유형별 패킷 특징:

스캔 유형명령어TCP 플래그특징
SYN Scannmap -sSSYN가장 흔함, Half-open
Connect Scannmap -sTFull handshake완전한 TCP 연결
FIN Scannmap -sFFIN스텔스 스캔
XMAS Scannmap -sXFIN,PSH,URGChristmas Tree
NULL Scannmap -sN(없음)플래그 없는 패킷
ACK Scannmap -sAACK방화벽 규칙 탐지
UDP Scannmap -sUUDPICMP 응답으로 판단

5-3. DDoS 패턴 분석

SYN Flood:

# 대량의 SYN 패킷이 다양한 소스 IP에서 동시에 유입
# Wireshark 필터
tcp.flags.syn == 1 and tcp.flags.ack == 0

# tcpdump로 SYN 패킷 카운트
sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0' -c 10000 2>&1 | tail -1
# 결과: "10000 packets captured" 가 수 초 만에 나오면 SYN Flood 의심

HTTP Flood:

# 동일 URL에 대한 대량 요청
# Wireshark 필터
http.request.uri == "/api/login"

# 초당 요청 수 확인
# Statistics > I/O Graph에서 http.request를 Y축으로 설정

DNS Amplification:

# DNS 응답이 쿼리보다 훨씬 큰 경우 (증폭 비율)
# 작은 쿼리 (60 bytes) → 큰 응답 (3000+ bytes)

# Wireshark 필터
dns.response and frame.len > 1000

# 증폭 비율 = 응답 크기 / 요청 크기
# ANY 쿼리의 증폭 비율: 약 28x ~ 54x

DDoS 탐지 체크리스트:

  1. I/O Graph에서 트래픽 급증 확인
  2. Conversations에서 상위 소스 IP 확인
  3. Protocol Hierarchy에서 특정 프로토콜 비율 급증 확인
  4. 동일 패턴의 반복적 요청 확인
  5. 비정상 소스 IP 대역 확인 (GeoIP 활용)

5-4. SQL Injection 탐지

HTTP POST Body에서 SQL 키워드를 검색합니다:

# Wireshark Display Filter
http.request.method == "POST" and (
  http contains "UNION" or
  http contains "SELECT" or
  http contains "DROP" or
  http contains "DELETE" or
  http contains "1=1" or
  http contains "OR 1" or
  http contains "--" or
  http contains "/*"
)

실제 SQL Injection 패킷 예시:

POST /api/login HTTP/1.1
Host: vulnerable-app.com
Content-Type: application/x-www-form-urlencoded

username=admin' OR '1'='1&password=anything

비정상 응답 크기 패턴:

  • 정상 로그인 실패 응답: 약 200 bytes
  • SQL Injection 성공 시: 수천 bytes (데이터 유출)
# 비정상 응답 크기 탐지
http.response and http.content_length > 10000

5-5. 데이터 유출 탐지

DNS Tunneling 탐지:

DNS Tunneling은 DNS 쿼리에 데이터를 인코딩하여 방화벽을 우회하는 기법입니다.

# 정상 DNS 쿼리
api.example.com (15)

# DNS Tunneling 쿼리 (비정상적으로 긴 도메인)
dGhpcyBpcyBhIHNlY3JldCBtZXNzYWdl.tunnel.evil.com (48)

Wireshark 필터:

# 비정상 길이 DNS 쿼리 탐지
dns.qry.name.len > 50

# TXT 레코드 쿼리 (tunneling에 자주 사용)
dns.qry.type == 16

# 특정 도메인에 대한 비정상 많은 쿼리
dns.qry.name contains "tunnel.evil.com"

비정상 아웃바운드 트래픽 탐지:

# tcpdump로 대용량 아웃바운드 모니터링
sudo tcpdump -i eth0 'src net 10.0.0.0/8 and dst net not 10.0.0.0/8 and greater 10000' -c 100

# 비정상 포트로의 아웃바운드
sudo tcpdump -i eth0 'src net 10.0.0.0/8 and not (dst port 80 or dst port 443 or dst port 53 or dst port 22)'

6. 보안 도구 생태계

6-1. Nmap: 네트워크 스캐너

Nmap은 네트워크 탐색과 보안 감사를 위한 오픈소스 도구입니다.

# 기본 포트 스캔
nmap 192.168.1.1

# 서비스 버전 탐지
nmap -sV 192.168.1.1

# OS 탐지
nmap -O 192.168.1.1

# 공격적 스캔 (서비스, OS, 스크립트, traceroute)
nmap -A 192.168.1.1

# 전체 포트 스캔
nmap -p- 192.168.1.1

# NSE 스크립트 활용
nmap --script vuln 192.168.1.1
nmap --script ssl-heartbleed 192.168.1.1
nmap --script http-sql-injection 192.168.1.1

6-2. Burp Suite: 웹 앱 보안 테스트

Burp Suite는 웹 애플리케이션 보안 테스트의 표준 도구입니다.

주요 기능:

  • Proxy: 브라우저와 서버 사이에서 요청/응답 가로채기 및 수정
  • Scanner: 자동 취약점 스캔 (SQL Injection, XSS, CSRF 등)
  • Intruder: 자동화된 공격 (Brute Force, Fuzzing)
  • Repeater: 개별 요청을 수정하여 반복 전송
  • Decoder: 인코딩/디코딩 도구

6-3. OWASP ZAP: 무료 웹 보안 스캐너

# Docker로 빠른 스캔
docker run -t zaproxy/zap-stable zap-baseline.py -t https://target.com

# API 스캔
docker run -t zaproxy/zap-stable zap-api-scan.py -t https://target.com/openapi.json -f openapi

# 전체 스캔
docker run -t zaproxy/zap-stable zap-full-scan.py -t https://target.com

6-4. Snort / Suricata: IDS/IPS

# Suricata 설치 (Ubuntu)
sudo apt install suricata

# 규칙 업데이트
sudo suricata-update

# IDS 모드로 실행
sudo suricata -c /etc/suricata/suricata.yaml -i eth0

# 커스텀 규칙 예시
# /etc/suricata/rules/local.rules
# alert http any any -> any any (msg:"SQL Injection Attempt"; content:"UNION SELECT"; nocase; sid:1000001; rev:1;)
# alert dns any any -> any any (msg:"DNS Tunneling Suspected"; dns.query; content:".tunnel."; nocase; sid:1000002; rev:1;)

6-5. Metasploit: 침투 테스트 프레임워크

# Metasploit 시작
msfconsole

# 취약점 검색
# msf6> search type:exploit platform:linux apache

# 모듈 사용 예시
# msf6> use exploit/multi/http/apache_log4j
# msf6> set RHOSTS target.com
# msf6> set RPORT 8080
# msf6> run

6-6. 도구 비교표

도구용도라이선스난이도주요 사용 대상
Wireshark패킷 분석무료/OSS중급네트워크 엔지니어, 개발자
tcpdumpCLI 패킷 캡처무료/OSS중급시스템 관리자
Nmap포트 스캐닝무료/OSS초급보안 엔지니어
Burp Suite웹 보안 테스트유료/무료판고급펜테스터
OWASP ZAP웹 보안 스캔무료/OSS중급개발자, QA
SnortIDS/IPS무료/OSS고급보안 운영
SuricataIDS/IPS무료/OSS고급보안 운영
Metasploit침투 테스트유료/무료판고급펜테스터

7. 제로 트러스트 아키텍처

7-1. 기본 원칙: Never Trust, Always Verify

전통적인 보안 모델은 "성(Castle)과 해자(Moat)" 접근법이었습니다. 내부 네트워크는 신뢰하고, 외부만 차단합니다. 하지만 이 모델은 내부 위협이나 VPN 침투 시 무력합니다.

제로 트러스트는 근본적으로 다릅니다:

전통적 모델:
  [인터넷] --방화벽-- [내부 네트워크: 모두 신뢰]
  → 내부 침투 시 횡적 이동(Lateral Movement) 자유

제로 트러스트:
  [모든 요청] --인증/인가-- [리소스]
  → 모든 접근마다 검증 (위치 무관)

핵심 원칙:

  1. 명시적 검증: 모든 요청을 인증, 인가, 암호화
  2. 최소 권한: 필요한 최소한의 권한만 부여 (Just-In-Time, Just-Enough-Access)
  3. 침해 가정: 이미 침해당했다고 가정하고 설계

7-2. 마이크로 세그먼테이션

네트워크를 작은 영역으로 분리하여 횡적 이동을 차단합니다:

전통적 네트워크:
  [Web Server] ←→ [App Server] ←→ [DB Server]
  모두 같은 VLAN, 자유로운 통신

마이크로 세그먼테이션:
  [Web Server] --정책-[App Server] --정책-[DB Server]
  각 통신에 별도 보안 정책 적용
  - WebApp: 포트 8080만 허용
  - AppDB: 포트 5432만 허용
  - WebDB: 차단

7-3. mTLS (상호 인증) 구현

일반 TLS는 서버만 인증하지만, mTLS는 클라이언트도 인증합니다:

일반 TLS:
  ClientServer: "당신이 진짜 서버인지 인증서로 증명해주세요"
  ServerClient: [서버 인증서 제시]
  → 클라이언트는 검증하지 않음

mTLS:
  ClientServer: "당신이 진짜 서버인지 증명해주세요"
  ServerClient: [서버 인증서] + "당신도 증명해주세요"
  ClientServer: [클라이언트 인증서]
  → 양방향 인증 완료

Node.js mTLS 서버 예시:

const https = require('https')
const fs = require('fs')

const options = {
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem'),
  ca: fs.readFileSync('ca-cert.pem'), // CA 인증서
  requestCert: true, // 클라이언트 인증서 요구
  rejectUnauthorized: true, // 유효하지 않은 인증서 거부
}

const server = https.createServer(options, (req, res) => {
  const clientCert = req.socket.getPeerCertificate()
  console.log('Client CN:', clientCert.subject.CN)
  res.writeHead(200)
  res.end('Mutual TLS authenticated!\n')
})

server.listen(443)

7-4. Service Mesh (Istio)에서의 보안

Istio는 마이크로서비스 간 통신에 자동으로 mTLS를 적용합니다:

# Istio PeerAuthentication - mTLS 강제
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: production
spec:
  mtls:
    mode: STRICT # mTLS 필수

---
# Istio AuthorizationPolicy - 세밀한 접근 제어
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: api-access
  namespace: production
spec:
  selector:
    matchLabels:
      app: api-server
  rules:
    - from:
        - source:
            principals: ['cluster.local/ns/production/sa/frontend']
      to:
        - operation:
            methods: ['GET', 'POST']
            paths: ['/api/v1/*']

7-5. 제로 트러스트와 Kubernetes

# Kubernetes NetworkPolicy - Pod 간 통신 제어
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-network-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-server
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: database
      ports:
        - protocol: TCP
          port: 5432
    - to: # DNS 허용
        - namespaceSelector: {}
      ports:
        - protocol: UDP
          port: 53

---
# Pod Security Standards
apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    fsGroup: 2000
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: app
      image: myapp:latest
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop:
            - ALL
      resources:
        limits:
          memory: '256Mi'
          cpu: '500m'

8. 개발자를 위한 보안 체크리스트

8-1. HTTPS 강제와 HSTS

# Nginx 설정
server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # HSTS 헤더 (2년, 서브도메인 포함, preload)
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    # TLS 설정
    ssl_protocols TLSv1.3 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
}

8-2. CORS 설정

// Express.js - 안전한 CORS 설정
const cors = require('cors')

const corsOptions = {
  origin: ['https://app.example.com', 'https://admin.example.com'],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400, // Preflight 캐시 24시간
}

app.use(cors(corsOptions))

// 절대 이렇게 하지 마세요:
// app.use(cors());  // 모든 오리진 허용 = 보안 취약

8-3. Rate Limiting

// Express.js - Rate Limiting
const rateLimit = require('express-rate-limit')

// 일반 API
const apiLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15분
  max: 100, // 최대 100 요청
  message: 'Too many requests, please try again later.',
  standardHeaders: true,
  legacyHeaders: false,
})

// 로그인 엔드포인트 (더 엄격)
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  message: 'Too many login attempts, please try again after 15 minutes.',
})

app.use('/api/', apiLimiter)
app.use('/api/login', loginLimiter)

8-4. Input Validation

// Joi를 사용한 입력 검증
const Joi = require('joi')

const userSchema = Joi.object({
  username: Joi.string().alphanum().min(3).max(30).required(),
  email: Joi.string().email().required(),
  password: Joi.string()
    .min(12)
    .pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])/)
    .required(),
  age: Joi.number().integer().min(13).max(120),
})

app.post('/api/register', (req, res) => {
  const result = userSchema.validate(req.body)
  if (result.error) {
    return res.status(400).json({
      error: result.error.details[0].message,
    })
  }
  // 검증 통과 후 처리
})

8-5. SQL Parameterized Queries

// Node.js + PostgreSQL - 안전한 쿼리
const { Pool } = require('pg')
const pool = new Pool()

// 절대 하지 마세요 (SQL Injection 취약):
// const query = `SELECT * FROM users WHERE id = ${userId}`;

// 올바른 방법: Parameterized Query
async function getUser(userId) {
  const result = await pool.query('SELECT id, username, email FROM users WHERE id = $1', [userId])
  return result.rows[0]
}

// ORM 사용 (Prisma)
async function getUserPrisma(userId) {
  return await prisma.user.findUnique({
    where: { id: userId },
    select: { id: true, username: true, email: true },
  })
}

8-6. JWT/OAuth2 보안

// JWT 보안 모범 사례
const jwt = require('jsonwebtoken')

// Access Token: 짧은 만료 시간
const accessToken = jwt.sign({ userId: user.id, role: user.role }, process.env.JWT_SECRET, {
  expiresIn: '15m', // 15분
  algorithm: 'RS256', // RSA 비대칭 키 사용
  issuer: 'api.example.com',
  audience: 'app.example.com',
})

// Refresh Token: DB에 저장, 회전(Rotation) 적용
const refreshToken = jwt.sign(
  { userId: user.id, tokenVersion: user.tokenVersion },
  process.env.REFRESH_SECRET,
  { expiresIn: '7d' }
)

// 검증 미들웨어
function verifyToken(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1]
  if (!token) return res.status(401).json({ error: 'No token' })

  try {
    const decoded = jwt.verify(token, process.env.JWT_PUBLIC_KEY, {
      algorithms: ['RS256'],
      issuer: 'api.example.com',
      audience: 'app.example.com',
    })
    req.user = decoded
    next()
  } catch (err) {
    return res.status(401).json({ error: 'Invalid token' })
  }
}

8-7. 시크릿 관리

# HashiCorp Vault 사용 예시
vault kv put secret/myapp/db \
  username="dbuser" \
  password="supersecret" \
  host="db.internal.example.com"

# 애플리케이션에서 읽기
vault kv get -field=password secret/myapp/db
// AWS Secrets Manager
const { SecretsManagerClient, GetSecretValueCommand } = require('@aws-sdk/client-secrets-manager')

async function getSecret(secretName) {
  const client = new SecretsManagerClient({ region: 'us-east-1' })
  const response = await client.send(new GetSecretValueCommand({ SecretId: secretName }))
  return JSON.parse(response.SecretString)
}

// 사용
const dbCreds = await getSecret('production/database')

8-8. 보안 헤더

// Helmet.js로 보안 헤더 설정
const helmet = require('helmet')

app.use(
  helmet({
    contentSecurityPolicy: {
      directives: {
        defaultSrc: ["'self'"],
        scriptSrc: ["'self'"],
        styleSrc: ["'self'", "'unsafe-inline'"],
        imgSrc: ["'self'", 'data:', 'https:'],
        connectSrc: ["'self'", 'https://api.example.com'],
        fontSrc: ["'self'", 'https://fonts.gstatic.com'],
        objectSrc: ["'none'"],
        mediaSrc: ["'none'"],
        frameSrc: ["'none'"],
      },
    },
    crossOriginEmbedderPolicy: true,
    crossOriginOpenerPolicy: true,
    crossOriginResourcePolicy: { policy: 'same-site' },
    hsts: { maxAge: 63072000, includeSubDomains: true, preload: true },
    noSniff: true, // X-Content-Type-Options: nosniff
    referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
    xssFilter: true, // X-XSS-Protection
  })
)

8-9. 의존성 취약점 스캔

# npm audit
npm audit
npm audit fix

# Snyk
npx snyk test
npx snyk monitor

# GitHub Dependabot (자동 PR 생성)
# .github/dependabot.yml
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: 'npm'
    directory: '/'
    schedule:
      interval: 'weekly'
    open-pull-requests-limit: 10
    reviewers:
      - 'security-team'
    labels:
      - 'dependencies'
      - 'security'

종합 보안 체크리스트:

항목중요도확인
HTTPS 강제 + HSTS필수-
TLS 1.2+ 만 허용필수-
CORS 화이트리스트필수-
Rate Limiting필수-
Input Validation필수-
Parameterized Queries필수-
JWT RS256 + 짧은 만료높음-
Refresh Token Rotation높음-
시크릿 매니저 사용필수-
CSP 헤더높음-
X-Content-Type-Options높음-
Referrer-Policy중간-
의존성 취약점 스캔필수-
Dependabot 활성화높음-
보안 로깅/모니터링필수-

9. 보안 자격증 로드맵

입문 → 중급 → 고급 경로

입문 (0~1년차):
  CompTIA Security+
  ├── 난이도: ★★☆☆☆
  ├── 비용:$404 (시험비)
  ├── 준비 기간: 2~3개월
  ├── 내용: 보안 기초, 위협, 암호화, 네트워크 보안
  └── 커리어 임팩트: IT 보안 입문, 정부/군 분야 필수

중급 (1~3년차):
  CEH (Certified Ethical Hacker)
  ├── 난이도: ★★★☆☆
  ├── 비용: 약 $1,199 (시험비)
  ├── 준비 기간: 3~4개월
  ├── 내용: 해킹 기법, 취약점 분석, 침투 테스트
  └── 커리어 임팩트: 보안 분석가, 펜테스터

  CISSP (보안 관리자 경로)
  ├── 난이도: ★★★★☆
  ├── 비용:$749 (시험비)
  ├── 준비 기간: 4~6개월 (경력 5년 필요)
  ├── 내용: 보안 관리, 거버넌스, 리스크 관리
  └── 커리어 임팩트: CISO, 보안 아키텍트

고급 (3년차+):
  OSCP (Offensive Security Certified Professional)
  ├── 난이도: ★★★★★
  ├── 비용: 약 $1,649 (교육 + 시험)
  ├── 준비 기간: 6~12개월
  ├── 내용: 24시간 실전 침투 테스트 시험
  └── 커리어 임팩트: 시니어 펜테스터, 레드팀

자격증별 상세 비교

자격증대상실기 비율갱신 주기평균 연봉 상승
CompTIA Security+입문자20%3년+15%
CEH중급자40%3년+20%
CISSP관리자0% (이론)3년+25%
OSCP전문가100% (실기)없음+35%
GPEN펜테스터60%4년+25%
CISM매니저0% (이론)3년+20%

개발자 추천 경로

웹 개발자:
  Security+CEHOSCPBug Bounty

클라우드 개발자:
  Security+AWS Security SpecialtyCCSP

DevOps 엔지니어:
  Security+CKS (Kubernetes Security)OSCP

10. 퀴즈

지금까지 배운 내용을 확인해 보겠습니다.

Q1. Wireshark에서 Capture Filter와 Display Filter의 가장 큰 차이점은?

정답: 적용 시점이 다릅니다.

  • Capture Filter: 캡처 시작 전에 설정하며, BPF 문법을 사용합니다. 커널 레벨에서 필터링하므로 성능이 좋지만 캡처 중 변경할 수 없습니다.
  • Display Filter: 캡처 후에 적용하며, Wireshark 자체 문법을 사용합니다. 이미 캡처된 데이터에서 필터링하므로 실시간으로 변경 가능합니다.

대용량 트래픽 환경에서는 Capture Filter로 필요한 트래픽만 캡처하고, Display Filter로 세밀하게 분석하는 것이 모범 사례입니다.

Q2. TLS 트래픽을 Wireshark에서 복호화하려면 어떤 환경변수를 설정해야 하나요?

정답: SSLKEYLOGFILE

SSLKEYLOGFILE 환경변수를 설정하면 Chrome, Firefox 등의 브라우저가 TLS 세션 키를 지정된 파일에 기록합니다. Wireshark에서 이 파일을 지정하면 (Edit - Preferences - Protocols - TLS) TLS로 암호화된 트래픽의 내용을 볼 수 있습니다.

주의: 이 기능은 개발/디버깅 환경에서만 사용해야 하며, 프로덕션 환경에서는 절대 사용하면 안 됩니다.

Q3. SYN Flood DDoS 공격을 Wireshark에서 탐지하려면 어떤 필터를 사용하나요?

정답: tcp.flags.syn == 1 and tcp.flags.ack == 0

이 필터는 ACK 플래그 없이 SYN 플래그만 설정된 패킷을 표시합니다. SYN Flood 공격은 대량의 SYN 패킷을 보내 서버의 TCP 연결 테이블을 가득 채우는 공격입니다.

추가로 Statistics - I/O Graphs에서 이 필터를 적용하면 시간대별 SYN 패킷 급증 패턴을 시각적으로 확인할 수 있습니다.

Q4. 제로 트러스트 보안 모델의 3가지 핵심 원칙은?

정답:

  1. 명시적 검증 (Verify Explicitly): 모든 요청을 항상 인증하고 인가합니다. 위치, 네트워크에 관계없이 모든 접근을 검증합니다.
  2. 최소 권한 (Least Privilege): Just-In-Time, Just-Enough-Access 원칙으로 필요한 최소한의 권한만 부여합니다.
  3. 침해 가정 (Assume Breach): 이미 침해당했다고 가정하고, 횡적 이동을 최소화하며, 엔드투엔드 암호화를 적용합니다.

전통적인 "성과 해자" 모델과 달리, 내부 네트워크도 신뢰하지 않는 것이 핵심입니다.

Q5. DNS Tunneling을 탐지하기 위해 확인해야 할 주요 지표는?

정답:

  1. 비정상적으로 긴 도메인 이름: 정상 DNS 쿼리는 보통 20-30자인 반면, DNS Tunneling은 50자 이상의 인코딩된 데이터를 포함합니다.
  2. TXT 레코드 쿼리 급증: DNS Tunneling은 더 많은 데이터를 전송하기 위해 TXT 레코드를 자주 사용합니다.
  3. 특정 도메인에 대한 비정상적 쿼리 빈도: 같은 도메인에 대해 초당 수십~수백 건의 쿼리가 발생합니다.

Wireshark 필터: dns.qry.name.len > 50 또는 dns.qry.type == 16 (TXT 레코드)으로 탐지할 수 있습니다.


11. 참고 자료

  1. Wireshark 공식 문서 - wireshark.org/docs
  2. tcpdump 매뉴얼 - tcpdump.org/manpages
  3. OWASP Top 10 (2025) - owasp.org/Top10
  4. NIST Zero Trust Architecture (SP 800-207) - csrc.nist.gov
  5. IBM Cost of a Data Breach Report 2025 - ibm.com/security
  6. Nmap Reference Guide - nmap.org/book/man.html
  7. Metasploit Unleashed - offensive-security.com/metasploit-unleashed
  8. SANS Network Forensics - sans.org/cyber-security-courses/network-forensics
  9. Practical Packet Analysis, 3rd Edition - Chris Sanders (No Starch Press)
  10. The Web Application Hacker's Handbook - Dafydd Stuttard, Marcus Pinto
  11. CompTIA Security+ Study Guide - comptia.org/certifications/security
  12. OSCP Certification Guide - offensive-security.com/pwk-oscp
  13. Suricata IDS Documentation - suricata.readthedocs.io
  14. Istio Security Documentation - istio.io/latest/docs/concepts/security
  15. Kubernetes Network Policies - kubernetes.io/docs/concepts/services-networking/network-policies
  16. OWASP ZAP Documentation - zaproxy.org/docs
  17. Burp Suite Documentation - portswigger.net/burp/documentation