Skip to content

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

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

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

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

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

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

| 순위 | 취약점 | 개발자 관련도 |

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

| 1 | Broken Access Control | 매우 높음 |

| 2 | Cryptographic Failures | 높음 |

| 3 | Injection (SQL, XSS, LDAP) | 매우 높음 |

| 4 | Insecure Design | 매우 높음 |

| 5 | Security Misconfiguration | 높음 |

| 6 | Vulnerable Components | 높음 |

| 7 | Authentication Failures | 매우 높음 |

| 8 | Data Integrity Failures | 높음 |

| 9 | Logging/Monitoring Failures | 보통 |

| 10 | SSRF (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 Filter | Display Filter |

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

| 적용 시점 | 캡처 시작 전 | 캡처 후 (실시간 변경 가능) |

| 문법 | BPF (Berkeley Packet Filter) | Wireshark 자체 문법 |

| 성능 | 높음 (커널 레벨 필터링) | 낮음 (모든 패킷 캡처 후 필터링) |

| 유연성 | 제한적 | 매우 유연 |

| 예시 | `host 192.168.1.1` | `ip.addr == 192.168.1.1` |

| 예시 | `port 80` | `tcp.port == 80` |

| 예시 | `tcp and port 443` | `tcp.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선

| 번호 | 필터 | 용도 |

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

| 1 | `ip.addr == 10.0.0.1` | 특정 IP 필터링 |

| 2 | `tcp.port == 443` | HTTPS 트래픽 |

| 3 | `tcp.port == 80` | HTTP 트래픽 |

| 4 | `http.request.method == "POST"` | POST 요청만 |

| 5 | `http.request.method == "GET"` | GET 요청만 |

| 6 | `dns.qry.name contains "example"` | 특정 도메인 DNS 쿼리 |

| 7 | `tcp.flags.syn == 1 and tcp.flags.ack == 0` | SYN 스캔 탐지 |

| 8 | `tcp.analysis.retransmission` | TCP 재전송 탐지 |

| 9 | `tcp.analysis.duplicate-ack` | 중복 ACK 탐지 |

| 10 | `tcp.analysis.zero-window` | Zero Window 탐지 |

| 11 | `http.response.code == 500` | 서버 에러 응답 |

| 12 | `http.response.code >= 400` | 모든 에러 응답 |

| 13 | `tls.handshake.type == 1` | TLS Client Hello |

| 14 | `tls.handshake.type == 2` | TLS Server Hello |

| 15 | `arp` | ARP 패킷만 |

| 16 | `icmp` | ICMP (ping) 패킷만 |

| 17 | `dns` | DNS 패킷만 |

| 18 | `tcp.analysis.flags` | TCP 문제가 있는 패킷 |

| 19 | `http.cookie contains "session"` | 세션 쿠키 포함 요청 |

| 20 | `frame.time_delta > 1` | 1초 이상 지연된 패킷 |

| 21 | `tcp.len > 0` | 데이터가 있는 TCP 패킷 |

| 22 | `ip.src == 10.0.0.0/8` | 내부 네트워크 소스 |

| 23 | `not arp and not dns` | ARP, DNS 제외 |

| 24 | `http.host contains "api"` | API 호출 필터링 |

| 25 | `tcp.stream eq 5` | 특정 TCP 스트림 |

| 26 | `frame.len > 1500` | MTU 초과 패킷 |

| 27 | `http.content_type contains "json"` | JSON 응답 |

| 28 | `tcp.analysis.lost_segment` | 손실 세그먼트 |

| 29 | `ip.ttl < 10` | 낮은 TTL (라우팅 문제) |

| 30 | `tls.handshake.extensions_server_name` | SNI 기반 필터링 |

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개

| 번호 | 명령어 | 용도 |

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

| 1 | `sudo tcpdump -i eth0` | 기본 캡처 |

| 2 | `sudo tcpdump -i eth0 -w capture.pcap` | 파일로 저장 |

| 3 | `sudo tcpdump -i eth0 host 10.0.0.1` | 특정 호스트 |

| 4 | `sudo tcpdump -i eth0 port 443` | 특정 포트 |

| 5 | `sudo tcpdump -i eth0 src 10.0.0.1` | 소스 IP 필터 |

| 6 | `sudo tcpdump -i eth0 dst port 80` | 목적지 포트 필터 |

| 7 | `sudo tcpdump -i eth0 net 192.168.0.0/24` | 서브넷 필터 |

| 8 | `sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0'` | SYN 패킷만 |

| 9 | `sudo tcpdump -i eth0 -c 1000 -w sample.pcap` | 1000개만 캡처 |

| 10 | `sudo tcpdump -i eth0 -nn port 53` | DNS 트래픽 |

| 11 | `sudo tcpdump -i eth0 icmp` | ICMP(ping)만 |

| 12 | `sudo tcpdump -i eth0 'port 80 and host 10.0.0.1'` | 복합 필터 |

| 13 | `sudo tcpdump -i eth0 -A port 80` | HTTP 내용 보기 |

| 14 | `sudo tcpdump -i eth0 'tcp[32:4] = 0x47455420'` | GET 요청만 |

| 15 | `sudo tcpdump -i eth0 greater 1000` | 1000바이트 초과 |

| 16 | `sudo tcpdump -i eth0 arp` | ARP 패킷만 |

| 17 | `sudo tcpdump -i eth0 -tttt -c 50 port 443` | 타임스탬프 포함 |

| 18 | `sudo tcpdump -i any port 8080` | 모든 인터페이스 |

| 19 | `sudo tcpdump -i eth0 not port 22` | SSH 제외 |

| 20 | `sudo 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 Scan | `nmap -sS` | SYN | 가장 흔함, Half-open |

| Connect Scan | `nmap -sT` | Full handshake | 완전한 TCP 연결 |

| FIN Scan | `nmap -sF` | FIN | 스텔스 스캔 |

| XMAS Scan | `nmap -sX` | FIN,PSH,URG | Christmas Tree |

| NULL Scan | `nmap -sN` | (없음) | 플래그 없는 패킷 |

| ACK Scan | `nmap -sA` | ACK | 방화벽 규칙 탐지 |

| UDP Scan | `nmap -sU` | UDP | ICMP 응답으로 판단 |

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 | 중급 | 네트워크 엔지니어, 개발자 |

| tcpdump | CLI 패킷 캡처 | 무료/OSS | 중급 | 시스템 관리자 |

| Nmap | 포트 스캐닝 | 무료/OSS | 초급 | 보안 엔지니어 |

| Burp Suite | 웹 보안 테스트 | 유료/무료판 | 고급 | 펜테스터 |

| OWASP ZAP | 웹 보안 스캔 | 무료/OSS | 중급 | 개발자, QA |

| Snort | IDS/IPS | 무료/OSS | 고급 | 보안 운영 |

| Suricata | IDS/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]

각 통신에 별도 보안 정책 적용

- Web → App: 포트 8080만 허용

- App → DB: 포트 5432만 허용

- Web → DB: 차단

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

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

일반 TLS:

Client → Server: "당신이 진짜 서버인지 인증서로 증명해주세요"

Server → Client: [서버 인증서 제시]

→ 클라이언트는 검증하지 않음

mTLS:

Client → Server: "당신이 진짜 서버인지 증명해주세요"

Server → Client: [서버 인증서] + "당신도 증명해주세요"

Client → Server: [클라이언트 인증서]

→ 양방향 인증 완료

**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+ → CEH → OSCP → Bug Bounty

클라우드 개발자:

Security+ → AWS Security Specialty → CCSP

DevOps 엔지니어:

Security+ → CKS (Kubernetes Security) → OSCP

10. 퀴즈

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

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

- **Capture Filter**: 캡처 시작 **전에** 설정하며, BPF 문법을 사용합니다. 커널 레벨에서 필터링하므로 성능이 좋지만 캡처 중 변경할 수 없습니다.

- **Display Filter**: 캡처 **후에** 적용하며, Wireshark 자체 문법을 사용합니다. 이미 캡처된 데이터에서 필터링하므로 실시간으로 변경 가능합니다.

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

**정답: SSLKEYLOGFILE**

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

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

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

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

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

**정답:**

1. **명시적 검증 (Verify Explicitly)**: 모든 요청을 항상 인증하고 인가합니다. 위치, 네트워크에 관계없이 모든 접근을 검증합니다.

2. **최소 권한 (Least Privilege)**: Just-In-Time, Just-Enough-Access 원칙으로 필요한 최소한의 권한만 부여합니다.

3. **침해 가정 (Assume Breach)**: 이미 침해당했다고 가정하고, 횡적 이동을 최소화하며, 엔드투엔드 암호화를 적용합니다.

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

**정답:**

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

현재 단락 (1/815)

2025년 IBM의 Cost of a Data Breach Report에 따르면, 데이터 유출 사고의 평균 비용은 **488만 달러**에 달합니다. 이는 전년 대비 10% 상승한 ...

작성 글자: 0원문 글자: 25,468작성 단락: 0/815