웹에서 공격이 발생할 수 있는 표면 영역이 증가함에 따라, Cloudflare의 웹 애플리케이션 방화벽(WAF) 은 이러한 공격을 완화하기 위한 수많은 솔루션을 제공합니다. 이는 Cloudflare 고객에게는 유용하지만, Cloudflare에서 서비스하는 수백만 건의 요청 워크로드에 있어 카디널리티로 인해 긍정 오류가 불가피합니다. 즉, 고객을 위한 기본 구성은 미세 조정되어야 합니다.
미세 조정은 어려운 프로세스가 아닙니다. 고객은 일부 데이터 포인트를 얻은 다음 자신에게 적합한 것을 결정해야 합니다. 이 게시물에서는 WAF가 특정 작업을 수행하는 이유를 고객들이 확인할 수 있도록 Cloudflare가 제공하는 기술들과, 노이즈를 줄이고 신호를 늘리기 위한 개선 사항들을 설명합니다.
로그 작업은 훌륭합니다. 더 많은 작업을 수행할 수 있을까요?
Cloudflare의 WAF 는 애플리케이션 계층을 대상으로 하는 공격인 다양한 종류의 애플리케이션 계층 공격으로부터 원본 서버를 보호합니다. 다음과 같은 다양한 도구로 보호할 수 있습니다.
이러한 도구는 Rulesets 엔진을 기반으로 합니다. 규칙 표현식과 일치하는 항목이 있으면 엔진이 작업을 실행합니다.
로그 작업은 규칙의 동작을 시뮬레이션하는 데 사용됩니다. 이렇게 하면 엔진이 규칙 표현식과 일치하는지 확인하고 보안 분석, 보안 이벤트, Logpush 또는 Edge Log Delivery를 통해 액세스할 수 있는 로그 이벤트를 방출합니다.
로그는 규칙이 일치할 것으로 예상된 트래픽에서 예상대로 작동하는지 확인하는 데는 훌륭하지만, 특히 규칙 표현식에 여러 코드 경로가 있을 수 있는 경우 규칙 일치를 보여주는 것으로는 충분하지 않습니다.
의사 코드에서 식은 다음과 같을 수 있습니다.
http 요청 헤더에 '인증' 키가 포함되어 있거나 http 호스트 헤더의 소문자 표현이 "cloudflare"로 시작하는 경우 theN log
규칙 언어 구문은 다음과 같습니다.
any(http.request.headers[*] contains "authorization") or starts_with(lower(http.host), "cloudflare")
이 표현식을 디버깅하면 몇 가지 문제가 발생합니다. 위 OR 표현식의 왼쪽(LHS) 아니면 오른쪽(RHS)이 일치하는 것은? Base64 디코딩, URL 디코딩, 이 경우 소문자 등의 기능은 이러한 필드의 원래 표현에 변환을 적용할 수 있으며, 이로 인해 요청의 어떤 특성이 일치하는지에 대한 모호성이 더욱 커집니다.
규칙 집합의 많은 규칙이 일치 항목을 등록할 수 있으므로 상황이 더욱 복잡해집니다. Cloudflare OWASP 와 같은 규칙 집합은 다양한 규칙의 누적 점수를 사용하여 점수가 설정된 임계값을 초과할 때 작업을 트리거합니다.
또한 Cloudflare Managed 및 OWASP 규칙의 표현은 비공개입니다. 이는 Cloudflare의 보안 상태를 강화하지만, 고객은 이러한 규칙이 제목, 태그 및 설명을 통해서만 무엇을 하는지 추측할 수 밖에 없습니다. 예를 들어, 레이블이 “SonicWall DMA - 원격 코드 실행 - CVE:CVE-2025-32819”일 수 있습니다.
다음과 같은 질문을 제기합니다. 요청의 어떤 부분이 규칙 집합 엔진의 일치로 이어졌습니까? 긍정 오류일까요?
바로 이 부분에서 악의적인 페이로드 로깅이 빛을 발합니다. 변환 후 일치를 가져온 규칙에서 특정 필드와 해당 값으로 자세히 분석하는 데 도움이 될 수 있습니다.
악의적인 페이로드 로깅은 WAF가 조치를 취하게 한 규칙과 연결된 요청의 필드를 기록하는 기능입니다. 이는 모호성을 줄이고, 오탐을 검사하고, 정확성을 보장하며, 더 나은 성능을 위해 이러한 규칙을 미세 조정하는 데 도움이 되는 유용한 정보를 제공합니다.
위 예에서 악의적인 페이로드 로그 항목은 표현식의 왼쪽 또는 오른쪽 중 하나를 포함하지만, 둘 모두를 포함하지는 않습니다.
악의적인 페이로드 로깅 및 규칙 집합 엔진은 Wirefilter에 구축되었으며, 이는 이미 자세히 설명되어 있습니다.
기본적으로 이러한 엔진은 Rust로 작성된 객체로서 컴파일러 특성을 구현합니다. 이러한 특성에 따라 이러한 표현식에서 파생된 추상 구문 트리(AST)가 컴파일됩니다.
struct PayloadLoggingCompiler {
regex_cache HashMap<String, Arc<Regex>>
}
impl wirefilter::Compiler for PayloadLoggingCompiler {
type U = PayloadLoggingUserData
fn compile_logical_expr(&mut self, node: LogicalExpr) -> CompiledExpr<Self::U> {
// ...
let regex = self.regex_cache.entry(regex_pattern)
.or_insert_with(|| Arc::new(regex))
// ...
}
}
규칙 세트 엔진은 표현식을 실행하며, 평가가 참이면 재평가를 위해 표현식과 실행 컨텍스트 가 악의적인 페이로드 로깅 컴파일러로 전송됩니다. 실행 컨텍스트는 표현식을 평가하는 데 필요한 모든 런타임 값을 제공합니다.
재평가가 완료된 후 true로 평가된 표현식 분기에 관련된 필드가 기록됩니다.
로그의 구조는 wirefilter 필드와 해당 값의 맵입니다 Map<Field, Value>
{
“http.host”: “cloudflare.com”,
“http.method”: “get”,
“http.user_agent”: “mozilla”
}
참고: 이러한 로그는 고객이 제공한 공개 키로 암호화됩니다.
이러한 로그는 로깅 파이프라인을 거치며 다양한 방식으로 읽을 수 있습니다. 고객은 Logpush 작업을 구성하여 당사가 구축한 사용자 지정 Worker에 작성하며, 이 Worker는 고객의 개인 키를 사용하여 이러한 로그를 자동으로 해독할 수 있습니다. 악의적인 페이로드 로깅 CLI 도구, Worker 또는 Cloudflare 대시보드를 사용해도 복호화할 수 있습니다.
wirefilter에서 일부 필드는 배열 유형입니다. http.request.headers.names 필드는 요청에 포함된 모든 헤더 이름의 배열입니다. 예:
[“content-type”, “content-length”, “authorization”, "host"]
헤더 중 하나 이상에 문자 "c"가 포함되어 있으므로 any(http.request.headers.names[*] contains “c”)라고 읽는 식은 true로 평가됩니다. 이전 버전의 악의적인 페이로드 로깅 컴파일러에서는 "http.request.headers.names" 필드는 true로 평가되는 표현식의 일부이므로 기록됩니다.
악의적인 페이로드 로그(이전)
http.request.headers.names[*] = [“content-type”, “content-length”, “authorization”, "host"]
이제 배열 필드를 부분적으로 평가하고 표현식 제약 조건과 일치하는 인덱스를 기록합니다. 이 경우 헤더에만 "c"가 포함됩니다!
악의적인 페이로드 로그(신규)
http.request.headers.names[0,1] = [“content-type”, “content-length”]
이제 wirefilter 연산자로 이동합니다. "eq"와 같은 일부 연산자는 정확히 일치합니다. http.host eq “a.com”. "in", "contains", "matches"와 같이 "부분적" 일치 결과를 초래하는 연산자가 정규 표현식과 함께 작동합니다.
예시에서의 표현식 `any(http.request.headers[*] contains “c”)`는 부분 일치를 생성하는 "contains" 연산자를 사용합니다. 또한 부분적으로 일치한다고 말할 수 있는 "any " 함수를 사용합니다. 헤더 중 적어도 하나에 "c"가 포함된 경우 모든 헤더를 기록해야 하는 것은 아닙니다(이전 버전에서처럼).
악의적인 페이로드 로깅 컴파일러가 개선되어 이러한 표현식을 평가할 때는 부분적으로 일치하는 부분만 기록합니다. 이 경우 새로운 악의적인 페이로드 로깅 컴파일러는 Rust 표준 라이브러리에서 바이트에 대한 "find" 메서드와 유사하게 "contains" 연산자를 처리합니다. 따라서 악의적인 페이로드 로그가 다음과 같이 개선됩니다.
http.request.headers.names[0,1] = [“c”, “c”]
따라서 상황이 훨씬 명확해집니다. 또한 로깅 파이프라인이 수백만 바이트를 처리하는 과정을 절약할 수 있습니다. 예를 들어, 많이 분석되는 필드는 요청 본문 — http.request.body.raw — 이며 그 크기가 수십 KB에 달할 수 있습니다. 때때로 표현식에서는 세 문자와 일치하는 정규식 패턴이 확인됩니다. 이 경우 킬로바이트 대신 3 바이트를 기록합니다!
저도 알아요, [“c”, “c”] 는 사실 큰 의미가 없습니다. 우리가 일치의 정확한 이유를 제공했고 고객의 스토리지 대상에 기록되는 바이트 양을 상당히 줄이고 있더라도 고객에게 유용한 디버깅 정보를 제공하는 것이 핵심 목표입니다. 페이로드 로깅 개선의 일환으로, 컴파일러는 이제 부분 일치에 대해 "이전" 및 "이후"(해당되는 경우)도 기록합니다. 이들 버퍼의 크기는 현재 각각 15바이트입니다. 즉, 악의적인 페이로드 로그는 다음과 같습니다.
http.request.headers[0,1] = [
{
before: null, // isnt included in the final log
content: “c”,
after: “ontent-length”
},
{
before: null, // isnt included in the final log
content: “c”,
after:”ontent-type”
}
]
악의적인 페이로드 로그 예시(이전)
악의적인 페이로드 로그 예시(신규)
이전 로그에는 모든 헤더 값이 있습니다. 새 로그에서 확인할 수 있는 것은 HTTP 헤더의 악의적 스크립트인 8번째 인덱스입니다. “<script>” 태그에서 일치하고 나머지는 회색 텍스트인 컨텍스트입니다.
관리형 규칙은 악의적 요청을 감지하기 위해 정규 표현식에 크게 의존합니다. 이러한 표현식을 구문 분석하고 컴파일하는 것은 CPU를 많이 사용하는 작업입니다. 관리 규칙은 한 번 작성되어 수백만 개의 영역에 배포되므로 이러한 정규식을 컴파일하고 메모리에 캐싱하면 이점이 있습니다. 이렇게 하면 프로세스가 다시 시작될 때까지 다시 컴파일할 필요가 없으므로 CPU 사이클이 절약됩니다.
악의적인 페이로드 로깅 컴파일러는 동적 크기의 배열 또는 벡터를 많이 사용하여 이러한 로그의 중간 상태를 저장합니다. smallvec 과 같은 크레이트는 힙 할당을 줄이는 데 사용되기도 합니다.
고객의 악의적인 페이로드 로그에 "잘린" 오류가 나타나는 경우가 있습니다. 모든 방화벽 이벤트에는 바이트 단위의 크기 제한이 있기 때문입니다. 이 제한을 초과하면 악의적인 페이로드 로그가 잘립니다.
악의적인 페이로드 로그(이전)
악의적인 페이로드 로그(신규)
저희는 악의적인 페이로드 로그의 p50바이트 크기가 1.5KB에서 500바이트로 67% 감소한 것을 확인했습니다! 즉, 잘린 악의적인 페이로드 로그가 줄어듭니다.
저희는 현재 값을 표현하기 위해 utf-8 문자열의 손실 표현을 사용하고 있습니다. 이는 멀티미디어와 같이 유효하지 않은 utf-8 문자열이 U+FFFD 유니코드 대체 문자로 표시됨을 의미합니다. 이진 데이터에 대해 작동하는 규칙의 경우 이러한 값의 무결성은 바이트 배열 또는 다른 직렬화 형식으로 유지되어야 합니다.
악의적인 페이로드 로깅의 스토리지 형식은 JSON입니다. CBOR, Cap'n Proto, Protobuf 등의 다른 바이너리 형식과 함께 이를 벤치마킹하여 처리 시간을 얼마나 많이 절약하는지 파이프라인을 절약할 예정입니다. 이는 바이너리 형식이 이전 버전과 호환되도록 정의된 스키마를 유지하는 데 도움이 될 수 있다는 추가적인 이점과 함께 로그를 고객에게 더 빠르게 전달하는 데 도움이 될 것입니다.
마지막으로, 악의적인 페이로드 로깅은 관리형 규칙에서만 작동합니다. 이는 사용자 지정 규칙, WAF attack score, 콘텐츠 스캐닝, Firewall for AI 등과 같은 다른 Cloudflare WAF 제품에도 적용될 것입니다.
AI용 방화벽에서 감지한, PII가 포함된 프롬프트를 보여주는 페이로드 로깅의 예:
WAF가 취한 조치를 볼 수 있게 되므로 고객은 규칙이나 구성이 정확히 예상대로 작동하는지 확인할 수 있습니다. 악의적인 페이로드 로깅의 특이성을 개선하는 것은 이러한 방향으로 한 걸음 더 나아가고 있으며, 안정성, 대기 시간 및 더 많은 WAF 제품으로의 확장을 위해 추가로 개선할 계획입니다.
이는 JSON 스키마의 주요 변경 사항이므로 적절한 문서와 함께 고객에게 천천히 배포했습니다.
페이로드 로깅을 시작하고 활성화하려면 개발자 문서를 방문하세요.