들어가며
이 글은 상용 DLP(Data Loss Prevention) 프로그램의 동작 원리를 분석하고, 윈도우 커널 드라이버 기반의 보안 솔루션을 직접 구현해보는 시리즈입니다.
지난 글에서는 WPF 트레이 앱 통신과 매체/파일 제어(USB & Minifilter)를 다뤘습니다. 이번 편에서는 네트워크 보안의 핵심인 WFP(Windows Filtering Platform) 기반 웹사이트 차단 시도와 일상적인 정보 유출 경로인 클립보드 차단 구현 과정을 공유합니다.
이전 글 보러가기
https://imoracle.tistory.com/74
[DLP 개발기] 3. WPF 트레이 앱 통신과 커널 레벨 매체/파일 제어 (USB & Minifilter)
들어가며이 글은 오피스키퍼 등 상용 DLP(Data Loss Prevention) 프로그램의 동작 원리를 분석하고, 윈도우 커널 드라이버 기반의 보안 솔루션을 직접 구현해보는 시리즈입니다.지난 2편에서는 커널 드
imoracle.tistory.com
다음 글 보러가기
https://imoracle.tistory.com/76
[DLP 개발기] 5. Minifilter 확장: 민감정보 패턴 검사와 파일 첨부 차단
들어가며이 글은 상용 DLP(Data Loss Prevention) 프로그램의 핵심 기능을 분석하고, 윈도우 커널 드라이버 기반으로 직접 구현해보는 시리즈입니다.지난 글에서는 네트워크 필터(WFP)의 한계와 유저모
imoracle.tistory.com
1. WFP 웹사이트 차단 - 왜 DNS 기반 차단을 선택했나?
웹사이트 접속을 차단하는 방법은 여러 가지가 있지만, 각각 뚜렷한 장단점이 존재합니다.
| 방식 | 설명 | 문제점 / 한계 |
| SSL Inspection | 자체 CA 인증서로 HTTPS 패킷을 복호화하여 검사 | 클라이언트마다 인증서 설치 필요, 구현 난이도 최상 |
| HTTP Host 파싱 | HTTP 패킷에서 Host 헤더 추출 | HTTPS 트래픽(암호화)에는 적용 불가 |
| IP 블랙리스트 | 차단 목록에 있는 IP로의 연결 차단 | 클라우드/CDN 환경에서는 사이트 IP가 수시로 변경됨 |
| DNS 쿼리 가로채기 | UDP 53 패킷을 뜯어 요청 도메인 검사 | DNS Client 서비스의 캐시 문제 (후술) |
(hosts 파일 변조도 존재하지만 원하는 방향은 아니기에 배제하였습니다.)
이 중에서 DNS 쿼리 가로채기는 HTTP/HTTPS 통신 여부와 무관하게 도메인 단위로 차단이 가능하고, 상용 DLP 제품들에서도 널리 쓰이는 형태라 구현 목표로 삼았습니다.
2. WFP 드라이버 구현: DNS 패킷 파싱
프로젝트 구성 및 헤더 함정
네트워크 패킷을 다루기 위해 WFP 프로젝트(OpenGuard_WFP)를 생성하고 구현을 시작했습니다. 여기서 WDK 개발자라면 한 번쯤 겪는 '헤더 Include 순서 함정'이 또 등장합니다.
// [주의] 반드시 이 순서를 지켜야 합니다.
#define NDIS_SUPPORT_NDIS6 1
#define NDIS60 1
#include <ntddk.h>
#include <wdm.h>
#include <initguid.h>
#include <ndis.h> // NET_BUFFER_LIST 정의를 위해 필요
#include <fwpmk.h>
#include <fwpsk.h>
ndis.h가 fwpsk.h보다 먼저 선언되지 않으면 NET_BUFFER_LIST 미정의 오류가 수백 개씩 쏟아집니다. 또한 NDIS 관련 매크로를 최상단에 정의해야 정상적으로 컴파일됩니다.
Callout 등록 및 패킷 파싱
WFP는 특정 네트워크 이벤트가 발생할 때 호출될 콜백(Callout)을 등록하는 구조입니다. DNS 패킷을 잡기 위해 FWPM_LAYER_DATAGRAM_DATA_V4(UDP 53) 레이어에 Callout을 등록했습니다.

UDP 53 패킷을 낚아챈 후, DNS 메시지 구조([헤더 12바이트] + [Questions] + [Answers])를 분석하여 쿼리 도메인 이름을 추출하는 함수(ExtractDnsName)를 구현했습니다. DebugView로 확인해 보니 사용자가 접속하려는 도메인들이 예쁘게 찍히는 것을 볼 수 있었습니다.

3. WFP DNS 차단의 뼈아픈 한계
"성공이다!"를 외치며 차단 로직을 얹었지만, 실제 웹 브라우저에서는 차단된 사이트가 버젓이 접속되는 현상이 발생했습니다. 원인은 Windows의 네트워크 아키텍처 자체에 있었습니다.

한계 1. Windows DNS Client 캐시
우리가 WFP로 잡은 UDP 53 패킷은 브라우저(Edge, Chrome)가 직접 보낸 것이 아닙니다.

브라우저는 백그라운드에 도는 DNS Client 서비스에 "이 도메인 IP 뭐야?"라고 물어봅니다. 만약 캐시에 IP가 남아있다면, 외부로 UDP 53 쿼리를 아예 날리지 않습니다. 즉, WFP 레이어에서 외부로 나가는 DNS 쿼리를 막더라도 브라우저는 이미 캐시된 IP로 접속해버리는 맹점이 생깁니다.
FWPM_LAYER_DATAGRAM_DATA_V4 레이어에서 방향(direction) 값을 확인한 결과
direction: 0 = 아웃바운드
direction: 1 = 인바운드
인바운드 패킷(DNS 응답)도 잡히지만 QR 비트가 항상 0(쿼리) 으로 찍혔습니다. DNS Client 서비스가 응답을 먼저 수신해서 처리하기 때문에 WFP 레이어까지 DNS 응답이 올라오지 않는 것으로 분석됩니다.
한계 2. DNS over HTTPS (DoH)
최근 브라우저들(Edge, Chrome 등)은 보안을 위해 DNS over HTTPS(DoH)를 기본적으로 활성화합니다. 이는 DNS 쿼리를 평문(UDP 53)이 아닌 암호화된 HTTPS(TCP 443) 패킷으로 감싸서 보냅니다. 당연히 WFP의 Datagram 레이어에서는 이를 전혀 감지할 수 없습니다.
결론: 상용 DLP는 어떻게 할까?
이러한 한계들 때문에 상용 엔드포인트 보안 솔루션들은 훨씬 로우레벨이거나 공격적인 방식을 택하는 걸로 보여집니다.
- NDIS Filter Driver 사용: WFP보다 더 낮은 패킷 드라이버 레벨에서 네트워크 흐름 전체를 통제. (구현 난이도 대폭 상승)
- DNS Client 무력화: 로컬 캐시를 끄고 앱이 직접 쿼리하게 유도. (다만 Windows 11 등 최신 OS에서는 부작용 큼)
- 완전한 SSL Inspection: 기업망에서 가장 많이 쓰이는 방식.
이번 프로젝트에서는 "WFP만으로 완벽한 DNS 차단은 어렵다"는 귀중한 아키텍처적 한계를 확인한 것에 의의를 두고, 다음 단계인 클립보드 제어로 넘어갔습니다. 후에 다시금 파볼 것 같지만서도.. 현재로썬 잘 모르겠네요
4. 유저모드 클립보드 차단

클립보드 차단은 굳이 커널로 내려갈 필요 없이 유저모드(에이전트)에서 충분히 구현 가능합니다. 핵심은 윈도우에서 발생하는 WM_CLIPBOARDUPDATE 메시지를 후킹하는 것입니다.
숨겨진 메시지 윈도우 (HWND_MESSAGE) 생성
클립보드 이벤트를 수신하려면 윈도우 핸들(HWND)이 필요한데, 백그라운드 에이전트는 화면이 없습니다. 이럴 때는 화면에 그려지지 않는 메시지 전용 윈도우를 생성하면 됩니다.

차단 로직 구현
메시지 루프(ClipWndProc)에서 클립보드 복사 이벤트가 감지되면, 전역 정책(g_ClipPolicy)을 확인합니다. 복사된 텍스트의 길이를 계산하여 정책 범위를 초과하면 EmptyClipboard() API를 호출해 클립보드를 날려버립니다.

이제 관리자 웹(PHP)에서 '최대 허용 글자 수'를 설정하면 30초 내에 에이전트로 전달되어 즉각적인 클립보드 통제가 이루어집니다.


복사를 하고 붙여넣기를 하려하면 클립보드에 아무것도 들어 있지않아 붙여넣기 버튼이 활성화조차 되지 않는 모습을 볼 수 있었습니다
트러블슈팅 정리 (삽질 노트)
| 발생 문제 | 원인 | 해결 방법 |
| NET_BUFFER_LIST 미정의 오류 | ndis.h 누락 및 헤더 순서 오류 | 최상단에 NDIS_SUPPORT_NDIS6 정의 후 ndis.h를 fwpsk.h보다 먼저 Include |
| GUID 링크 오류 | 공유 헤더의 C/C++ 혼용 선언 문제 | __cplusplus 매크로를 분기하여 C++에서는 extern "C"로, C에서는 DEFINE_GUID로 분리 선언 |
| WFP 드라이버 등록 시 FWP_E_NULL_POINTER | Callout 등록 시 DeviceObject 누락 | IoCreateDevice로 디바이스 객체를 먼저 생성한 후 FwpsCalloutRegister에 파라미터로 전달 |
| 에이전트(C++) 즉시 종료 (크래시) | CRITICAL_SECTION 초기화 시점 오류 | 동기화 객체(InitializeCriticalSection)를 정책 폴링 스레드 시작 전에 명시적으로 초기화 |
| 정책 업데이트 시 블루스크린(BSOD) | 컴포넌트 간 정책 구조체 크기 불일치 | OG_POLICY 구조체 필드 추가 후 드라이버/에이전트 모두 Clean Build 및 sys 파일 교체 |
마무리 및 다음 편 예고
이번 편을 통해 WFP의 강력함 이면에 숨겨진 Windows OS 네이티브 서비스(DNS Client)와의 구조적 충돌을 몸소 경험했습니다. 단순히 패킷을 드롭하는 코드를 짜는 것과, OS의 아키텍처를 뚫고 상용 수준의 차단을 구현하는 것은 차원이 다른 문제라는 것을 깨달았습니다.
다음 글에서는 다시 커널로 돌아가서, Minifilter를 깊게 활용한 민감정보 패턴 검사(정규식)와 파일 첨부 차단 로직을 다루어 보겠습니다.
긴 글 읽어주셔서 감사합니다 !
이전 글 보러가기
https://imoracle.tistory.com/74
[DLP 개발기] 3. WPF 트레이 앱 통신과 커널 레벨 매체/파일 제어 (USB & Minifilter)
들어가며이 글은 오피스키퍼 등 상용 DLP(Data Loss Prevention) 프로그램의 동작 원리를 분석하고, 윈도우 커널 드라이버 기반의 보안 솔루션을 직접 구현해보는 시리즈입니다.지난 2편에서는 커널 드
imoracle.tistory.com
다음 글 보러가기
https://imoracle.tistory.com/76
[DLP 개발기] 5. Minifilter 확장: 민감정보 패턴 검사와 파일 첨부 차단
들어가며이 글은 상용 DLP(Data Loss Prevention) 프로그램의 핵심 기능을 분석하고, 윈도우 커널 드라이버 기반으로 직접 구현해보는 시리즈입니다.지난 글에서는 네트워크 필터(WFP)의 한계와 유저모
imoracle.tistory.com
'Project > [DLP] OpenGuard' 카테고리의 다른 글
| [DLP 개발기] 5. Minifilter 확장: 민감정보 패턴 검사와 파일 첨부 차단 (0) | 2026.05.08 |
|---|---|
| [DLP 개발기] 3. WPF 트레이 앱 통신과 커널 레벨 매체/파일 제어 (USB & Minifilter) (0) | 2026.05.06 |
| [DLP 개발기] 2. 커널 드라이버와 IOCTL, 그리고 E2E 파이프라인 구축 (0) | 2026.04.29 |
| [DLP 개발기] 1. 커널 드라이버 기반 보안 시스템, OpenGuard 시작하기 (0) | 2026.04.29 |