방화벽 패킷 필터링
서버를 인터넷에 연결하면 누구나 그 서버에 패킷을 보낼 수 있습니다. 그 가운데는 정상적인 사용자의 요청도 있지만, 열려 있는 모든 포트를 두드려 보는 스캔이나 공격 시도도 섞여 있습니다. 방화벽(firewall)은 네트워크의 경계나 서버 앞에서 들어오고 나가는 트래픽을 규칙에 따라 허용하거나 차단하는 장치(또는 소프트웨어)입니다. 건물의 출입문에서 출입증을 확인하는 경비와 비슷합니다. 가장 기본적인 방식인 패킷 필터링은 패킷 헤더의 출발지와 목적지 IP 주소, 포트 번호, 프로토콜 같은 값을 규칙과 비교해 통과 여부를 정합니다.
iptables나 네트워크 ACL처럼 규칙에 순서가 있는 방화벽은 위에서부터 차례로 비교해 처음 일치한 규칙을 적용하기 때문에 순서가 중요하고, 어느 규칙에도 일치하지 않는 패킷은 기본 정책이 정합니다. 또한 응답 패킷을 어떻게 통과시킬지에 따라 상태를 보지 않는 방식과 연결 상태를 추적하는 상태 기반(stateful) 방식으로 나뉩니다. 이 토픽에서는 규칙이 매칭되는 과정, 상태 추적이 응답을 처리하는 방식, 기본 거부와 기본 허용의 차이를 단계별로 봅니다.
핵심 개념
패킷 필터링
패킷 헤더의 출발지 · 목적지 IP, 포트 번호, 프로토콜(TCP, UDP 등)을 규칙과 비교해 허용하거나 차단합니다. 패킷의 내용(페이로드)은 보지 않는 것이 기본입니다.
핵심 개념
규칙과 매칭 순서
iptables, nftables, 네트워크 ACL처럼 순서가 있는 규칙은 위에서부터 차례로 비교해 처음 일치한 규칙의 동작을 적용합니다(AWS 보안 그룹은 허용 규칙만 있어 순서가 없습니다). 그래서 구체적인 규칙을 위에, 넓은 규칙을 아래에 두는 순서가 결과를 바꿉니다.
핵심 개념
기본 정책
어떤 규칙에도 일치하지 않는 패킷을 어떻게 할지 정하는 설정입니다. 기본 거부(default deny)는 허용한 것만 통과시키고, 기본 허용은 차단한 것만 막습니다.
핵심 개념
상태 기반 방화벽
연결 상태를 표로 추적해, 허용된 연결의 응답 패킷은 별도 규칙 없이 통과시킵니다. 표에 없는 패킷은 허용 규칙에 일치하지 않으면(보통 인바운드 기본 거부) 차단합니다.
핵심 개념
인바운드와 아웃바운드
밖에서 안으로 들어오는 방향이 인바운드, 안에서 밖으로 나가는 방향이 아웃바운드입니다. 보통 인바운드는 엄격하게, 아웃바운드는 비교적 느슨하게 정합니다.
핵심 개념
애플리케이션 계층 방화벽
헤더뿐 아니라 HTTP 요청 같은 응용 계층의 내용을 보고 판단하는 방화벽입니다. 웹 공격을 막는 웹 애플리케이션 방화벽(WAF)이 한 예입니다.
방화벽의 배경
방화벽은 라우터 같은 장비에서 패킷을 걸러 내는 패킷 필터링으로 시작되었고, 이후 연결 상태를 추적하는 상태 기반 방식, 연결을 둘로 나눠 중계하며 내용을 검사하는 프록시 방식, 응용 계층까지 보는 방식이 등장했습니다. 개념과 설계 원칙은 NIST의 방화벽 가이드(SP 800-41)에 정리되어 있습니다. 오늘날에는 전용 장비뿐 아니라 운영체제 커널의 필터링 기능(리눅스의 netfilter 등), 클라우드의 보안 그룹처럼 소프트웨어로도 흔히 쓰입니다.
숫자로 확인하기
자주 하는 오해
면접에서 이렇게 물어요
면접 질문
방화벽은 무엇이고 어떻게 동작하나요?
네트워크 트래픽을 규칙에 따라 허용하거나 차단하는 장치입니다. 패킷 필터링 방화벽은 패킷 헤더의 IP 주소, 포트, 프로토콜을 규칙과 위에서부터 비교해 처음 일치한 규칙을 적용합니다.
면접 질문
상태 기반 방화벽은 무엇이 다른가요?
연결 상태 표를 유지해, 허용된 연결에 대한 응답 패킷을 별도 규칙 없이 통과시킵니다. 상태를 보지 않는 필터보다 규칙을 단순하고 안전하게 만들 수 있습니다.
면접 질문
기본 정책은 어떻게 정하는 게 좋은가요?
기본 거부(default deny)가 권장됩니다. 필요한 트래픽만 명시적으로 허용하면 규칙에서 빠뜨린 트래픽이 자동으로 차단되어, 실수가 구멍이 되지 않습니다.
면접 질문
방화벽과 NAT는 어떻게 다른가요?
NAT는 주소를 바꾸는 기술이고 방화벽은 트래픽을 허용하거나 차단하는 정책 장치입니다. NAT 때문에 외부 접속이 막히는 효과가 있어도 접근 제어의 용도는 아닙니다.
실제 시스템에서는
함께 보면 좋은 토픽
참고 자료
iptables — 기본 거부와 상태 기반 규칙
# 확립된 연결과 관련 연결, 로컬 통신은 통과 (상태 기반) sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT sudo iptables -A INPUT -i lo -j ACCEPT # 필요한 것만 명시적으로 허용 sudo iptables -A INPUT -p tcp -s 10.0.0.0/8 --dport 22 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT # 허용 규칙을 모두 넣은 뒤 마지막에 기본 정책을 차단으로 바꾼다 sudo iptables -P INPUT DROP # 규칙을 순서대로 보기 sudo iptables -L INPUT -n -v --line-numbers
iptables -P INPUT DROP은 INPUT 사슬의 기본 정책을 차단으로 정해, 어느 규칙에도 일치하지 않는 패킷이 모두 버려지게 합니다. 규칙은 -A로 사슬의 끝에 차례로 추가되며 위에서부터 비교해 처음 일치한 규칙의 ACCEPT나 DROP 같은 종결 동작이 적용됩니다(LOG처럼 다음 규칙으로 넘어가는 동작도 있습니다). conntrack의 ESTABLISHED는 양방향 패킷이 확인된 연결의 패킷(서버가 시작한 연결의 응답 포함)을, RELATED는 FTP 데이터 연결이나 ICMP 오류처럼 기존 연결과 연관된 새 패킷을 통과시켜 상태 기반 방화벽이 되게 하는 핵심 규칙입니다. 이 규칙이 없으면 서버가 시작한 연결의 응답도 기본 정책에 막힙니다. 원격으로 접속 중인 서버에서는 SSH 허용 규칙을 먼저 넣고 기본 정책을 DROP으로 바꾸는 일을 마지막에 해야 접속이 끊기지 않으며(위 코드의 순서), 이 명령은 재부팅하면 사라집니다.
nftables — 같은 정책을 규칙 집합으로
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iif lo accept
ip saddr 10.0.0.0/8 tcp dport 22 accept
tcp dport 443 accept
}
}
nftables는 iptables를 잇는 리눅스의 패킷 필터링 프레임워크로, 규칙을 table 안의 chain에 계층 구조로 적습니다. policy drop은 기본 거부를, ct state established,related accept는 연결 추적 상태가 확립됨 또는 관련됨인 패킷의 허용을 뜻합니다. 나머지 두 줄은 앞의 iptables 예와 같은 허용 규칙(내부망의 SSH, 모든 곳의 HTTPS)입니다. 다만 iptables 예는 IPv4만 다루고, inet 테이블은 IPv4와 IPv6에 모두 적용되며 ip saddr 규칙은 IPv4 패킷만 일치시킵니다. 규칙은 위에서부터 평가되어 처음 일치한 것이 적용됩니다. 위 코드는 구조를 보이는 최소 예시이며, 실제 적용은 배포판의 nftables 설정 방법을 따라야 합니다.
Python — 규칙 평가기 흉내 내기
import ipaddress RULES = [ ("allow", "tcp", "10.0.0.0/8", 22), ("allow", "tcp", "0.0.0.0/0", 443), ("deny", "tcp", "0.0.0.0/0", 23), ] def decide(proto, src_ip, dst_port): for action, r_proto, r_src, r_port in RULES: if (proto == r_proto and dst_port == r_port and ipaddress.ip_address(src_ip) in ipaddress.ip_network(r_src)): return action # 처음 일치한 규칙을 적용 return "deny" # 일치하는 규칙이 없으면 기본 거부 print(decide("tcp", "10.0.0.7", 22)) # allow print(decide("tcp", "198.51.100.9", 22)) # deny print(decide("tcp", "198.51.100.9", 443)) # allow print(decide("udp", "198.51.100.9", 53)) # deny (기본 거부)
이 함수는 시각화의 규칙 매칭 탭과 같은 판단을 합니다. 규칙 목록을 위에서부터 돌며 프로토콜, 출발지 주소 범위, 목적지 포트가 모두 일치하는 첫 규칙의 동작을 돌려주고, 어디에도 일치하지 않으면 기본 거부인 deny를 돌려줍니다. ipaddress.ip_network로 출발지 주소 범위를 표현하고 in 연산자로 어느 범위에 속하는지 확인하는 것은 서브네팅 토픽에서 본 접두사 비교와 같습니다. 실제 방화벽은 연결 상태, 방향, 인터페이스, 로그 같은 조건과 동작을 더 지원하므로 이 코드는 원리만 보이는 최소 예시입니다.
Q1
패킷 필터링 방화벽이 주로 검사하는 정보는?
Q2
상태 기반(Stateful) 방화벽의 특징은?
Q3
보안상 권장되는 방화벽의 기본 정책은?