커스텀 규칙 언어 속성 구성

각 Google Cloud Armor 보안 정책 규칙에는 우선순위, 일치 조건, 작업이 있습니다. Google Cloud Armor는 요청과 일치하는 우선순위가 가장 높은 규칙의 작업을 수행합니다. 우선순위가 가장 높은 일치 규칙보다 우선순위가 낮은 규칙은 일치 조건이 동일하더라도 평가되지 않습니다.

각 보안 정책 규칙은 두 가지 유형의 일치 조건을 지원합니다.

  • 기본 일치 조건에는 IP 주소 목록 또는 IP 주소 범위 목록이 포함됩니다. Google Cloud CLI를 사용하여 규칙을 만들 때 --src-ip-ranges 플래그를 사용하여 기본 일치 조건을 정의합니다.
  • 고급 일치 조건에는 들어오는 요청의 다양한 속성과 일치할 수 있는 최대 5개의 하위 표현식이 있는 표현식이 포함됩니다. Google Cloud CLI를 사용하여 규칙을 만들 때 --expression 플래그를 사용하여 고급 일치 조건을 정의합니다.

이 페이지에서는 고급 일치 조건에 대해 설명하며 보안 정책 규칙의 고급 일치 조건에서 표현식을 작성하는 데 사용하는 Google Cloud Armor 커스텀 규칙 언어에 대해서도 다룹니다. Google Cloud Armor 커스텀 규칙 언어는 Common Expression Language(CEL)의 하위 집합입니다. Google Cloud Armor 커스텀 규칙 언어로 작성된 표현식에는 두 가지 구성요소가 필요합니다.

  • 속성: 검사할 데이터
  • 작업: 데이터 사용 방법

예를 들어 다음 표현식은 inIpRange() 작업의 origin.ip 속성과 9.9.9.0/24 속성을 사용합니다. 이 경우 origin.ip9.9.9.0/24 IP 주소 범위 내에 있으면 표현식은 true를 반환합니다.

inIpRange(origin.ip, '9.9.9.0/24')

이전 예시 표현식은 소스 IP 주소에서만 일치하지만 Google Cloud Armor 보안 정책 규칙에서 예시 표현식을 사용할 때 규칙은 고급 일치 조건이 있는 규칙으로 간주됩니다. 자세한 내용은 Google Cloud Armor 할당량 및 한도를 참조하세요.

속성

속성은 원본 IP 주소 또는 요청된 URL 경로와 같은 들어오는 요청의 정보를 나타냅니다.

필드 유형 필드 설명
origin.ip 문자열 요청의 소스 IP 주소입니다.
origin.user_ip 문자열 업스트림 프록시에 의해 HTTP-HEADER에 포함된 원본 클라이언트의 IP 주소입니다. 이 속성을 사용하기 전에 보안 정책의 advancedOptionsConfig 필드에서 True-Client-IP, X-Forwarded-For, 또는 X-Real-IP와 같은 소스와 일치하도록 userIpRequestHeaders[] 옵션을 구성해야 합니다.

userIpRequestHeaders[] 옵션을 구성하지 않은 경우, 구성된 헤더에 잘못된 IP 주소 값이 포함된 경우, 구성된 헤더가 없는 경우 origin.user_ip의 기본값은 origin.ip입니다. 자세한 내용은 securityPolicy 리소스 참조를 확인하세요.

origin.tls_ja3_fingerprint 문자열 클라이언트가 HTTPS, HTTP/2, HTTP/3을 사용하여 연결하는 경우 JA3 TLS/SSL 디지털 지문입니다. 사용할 수 없으면 빈 문자열이 반환됩니다.
request.headers 지도 HTTP 요청 헤더의 문자열 대 문자열 지도입니다. 헤더에 값이 여러 개 포함된 경우 이 지도의 값은 모든 헤더 값의 쉼표로 구분된 문자열입니다. 이 지도의 키는 모두 소문자입니다. 외부 애플리케이션 부하 분산기에서 허용하는 모든 헤더가 검사되고 동일한 헤더 제한사항이 적용됩니다.

먼저 has(request.headers['header-key']) && request.headers['header-key'] != 'header-value'와 같은 has()를 사용하여 가용성을 확인하는 것이 좋습니다.

request.method 문자열 GET 또는 POST와 같은 HTTP 요청 메서드입니다.
request.path 문자열 요청한 HTTP URL 경로
request.scheme 문자열 http 또는 https와 같은 HTTP URL 스키마입니다. 이 속성 값은 모두 소문자입니다.
request.query 문자열 HTTP 요청의 첫 번째 행에 표시되는 name1=value&name2=value2 형식의 HTTP URL 쿼리입니다. 디코딩이 수행되지 않습니다.
origin.region_code 문자열 원본 IP와 연결된 유니코드 국가 코드입니다(예: US). ISO 3166-1 alpha 2 국가 또는 리전 코드를 사용하는 규칙이나 표현식을 만들면 Google Cloud Armor는 각 코드를 독립적으로 처리합니다. Google Cloud Armor 규칙과 표현식은 리전 코드를 명시적으로 사용하여 요청을 허용하거나 거부합니다.

자세한 내용은 유니코드 기술 표준의 unicode_region_subtag를 참조하세요.

origin.asn 정수 원본 IP 주소와 연결된 자율 시스템 번호(ASN)입니다. 전역적으로 고유한 ASN은 원본 IP 주소가 포함된 IP 주소 프리픽스를 지원하는 네트워크 연산자를 기반으로 결정됩니다.

reCAPTCHA 속성

이 섹션에는 reCAPTCHA 토큰 또는 예외 쿠키에만 적용되는 속성이 나와 있습니다. 이러한 속성을 기반으로 하는 하위 표현식은 다음과 같은 이유로 평가할 reCAPTCHA 토큰 또는 예외 쿠키가 제공되지 않거나 잘못된 경우 false를 반환합니다.

  • 토큰 형식이 잘못되었으며 디코딩할 수 없습니다.
  • 토큰에 잘못된 속성이 있습니다. 예를 들어 규칙의 연결된 reCAPTCHA 키와 일치하지 않는 reCAPTCHA 키를 사용해 토큰이 생성되었습니다.
  • 토큰이 만료되었습니다.
필드 유형 필드 설명
token.recaptcha_exemption.valid bool 유효한 reCAPTCHA 예외 쿠키의 존재입니다.

작업 토큰 속성

필드 유형 필드 설명
token.recaptcha_action.score float reCAPTCHA 작업 토큰의 점수입니다. 유효한 점수의 범위는 0.0부터 1.0까지이며 0.0은 불법 사용자일 가능성이 매우 높으며 1.0은 적법한 사용자일 가능성이 높습니다.
token.recaptcha_action.captcha_status string reCAPTCHA 작업 토큰의 보안문자 상태입니다. 유효한 상태는 NONE, PASS 또는 FAIL이며, 여기서 NONE은 reCAPTCHA 평가 중에 관련 챌린지가 없음을 나타냅니다(예: 보안문자 필드가 작업 토큰에 누락됨).
token.recaptcha_action.action string reCAPTCHA 작업 토큰의 작업 이름(영문 기준 최대 100자)입니다. 작업 이름을 참조하세요.
token.recaptcha_action.valid bool 유효한 reCAPTCHA 작업 토큰의 존재입니다.

세션 토큰 속성

필드 유형 필드 설명
token.recaptcha_session.score float reCAPTCHA 세션 토큰의 점수입니다. 유효한 점수의 범위는 0.0부터 1.0까지이며 0.0은 불법 사용자일 가능성이 매우 높으며 1.0은 적법한 사용자일 가능성이 높습니다.
token.recaptcha_session.valid bool 유효한 reCAPTCHA 세션 토큰의 존재입니다.

운영

다음 참조는 규칙 표현식을 정의하도록 속성(x, y, k으로 표시)과 함께 사용할 수 있는 연산자를 설명합니다.

표현식 설명
x == "foo" x가 주어진 상수 문자열 리터럴과 같으면 true를 반환합니다.
x == R"fo'o" x가 이스케이프 문자 시퀀스를 해석하지 않는 지정된 원시 문자열 리터럴과 같으면 true를 반환합니다. 원시 문자열 리터럴은 이스케이프 시퀀스 문자를 사용해야 하는 문자열을 표현하는 데 편리합니다.
x == y xy와 같으면 true를 반환합니다.
x != y xy와 같지 않으면 true를 반환합니다.
x + y 연결된 문자열 xy를 반환합니다.
x && y xy가 모두 true이면 true를 반환합니다.
x || y x, y 또는 둘 다 true이면 true를 반환합니다.
!x 불리언 값 x가 false이면 true를 반환하고 부울값 x가 true이면 false를 반환합니다.
x.contains(y) 문자열 x에 하위 문자열 y가 있으면 true를 반환합니다.
x.startsWith(y) 문자열 x가 하위 문자열 y로 시작하면 true를 반환합니다.
x.endsWith(y) 문자열 x가 하위 문자열 y로 끝나면 true를 반환합니다.
x.matches(y) 문자열 x가 지정된 RE2 패턴 y와 부분적으로 일치하면 true를 반환합니다. RE2 패턴은 유니코드 기능을 사용 중지하는 RE2::Latin1 옵션을 통해 컴파일됩니다.
inIpRange(x, y) IP 주소 x가 IP 범위 y 내에 포함되어 있으면 true를 반환합니다.
x.lower() 문자열 x의 소문자 값을 반환합니다.
x.upper() 문자열 x의 대문자 값을 반환합니다.
x.base64Decode() base64로 디코딩된 x값을 반환합니다. 문자 _ -는 먼저 각각 / +로 바뀝니다. x가 유효한 base64 값이 아니면 ""(빈 문자열)를 반환합니다.
has(m['k']) k에서 키 k를 사용할 수 있으면 true를 반환합니다.
m['k'] k를 사용할 수 있으면 문자열 간 맵 m에서 키 k의 값을 반환하고 그렇지 않으면 오류를 반환합니다. 먼저 "has(m['k'])==true"를 사용하여 가용성을 확인하는 것이 좋습니다.
int(x) x의 문자열 결과를 int 유형으로 변환합니다. 그러면 > 와 <= 같은 표준 산술 연산자를 사용하여 정수 비교를 수행하는 데 사용할 수 있으며 정수여야 하는 값에만 작동합니다.
size(x) 문자열 x의 길이를 반환합니다.
x.urlDecode() URL로 디코딩된 x 값을 반환합니다. %## 형식의 문자 시퀀스는 ASCII가 아닌 문자 시퀀스로 바뀌고 +은 공백으로 바뀝니다. 잘못된 인코딩은 있는 그대로 반환됩니다.
x.urlDecodeUni() URL로 디코딩된 x 값을 반환합니다. 이렇게 하면 urlDecode() 외에도 %u### 형식의 유니코드 문자 시퀀스가 처리됩니다. 잘못된 인코딩은 있는 그대로 반환됩니다.
x.utf8ToUnicode() UTF-8로 인코딩된 xx 유니코드 표현식을 반환합니다.

표현식 예시

이러한 표현식마다 수행되는 작업은 표현식이 거부 또는 허용 규칙에 포함되는지 여부에 따라 다릅니다.

IPv4 또는 IPv6의 IP 주소 범위를 기준으로 액세스 허용 또는 거부

  • 다음 표현식은 198.51.100.0/24 IP 주소 범위의 요청과 일치합니다.

    inIpRange(origin.ip, '198.51.100.0/24')
    
  • 다음 표현식은 2001:db8::/32 IP 주소 범위의 요청과 일치합니다.

    inIpRange(origin.ip, '2001:db8::/32')
    

업스트림 프록시 뒤의 커스텀 클라이언트 IP 주소 범위를 기준으로 액세스 허용 또는 거부

origin.user_ip 연산자를 구성한 경우 advancedOptionsConfig.userIpRequestHeaders[] 필드에서 지정한 헤더 값을 기준으로 일치시킬 수 있습니다.

  • 다음 표현식은 192.0.2.0/24 IP 주소 범위에서 시작된 요청과 일치합니다.

    inIpRange(origin.user_ip, '192.0.2.0/24')
    
  • 다음 표현식은 2001:db8::/32 IP 주소 범위에서 시작된 요청과 일치합니다.

    inIpRange(origin.user_ip, '2001:db8::/32')
    
  • 다음 표현식은 80=BLAH가 포함된 쿠키가 있는 요청과 일치합니다.

    has(request.headers['cookie']) && request.headers['cookie'].contains('80=BLAH')
    

비어 있지 않은 referer 헤더가 있는 트래픽 허용 또는 거부

  • 다음 표현식은 비어 있지 않은 referer 헤더가 있는 요청과 일치합니다.

    has(request.headers['referer']) && request.headers['referer'] != ""
    

헤더의 호스트 URL을 기준으로 트래픽 허용 또는 거부

  • 다음 표현식은 특정 URL에 대한 요청과 일치합니다.

    request.headers['host'].lower().contains('test.example.com')
    

특정 리전의 트래픽 허용 또는 거부

AU 리전에서 웹 애플리케이션을 사용할 수 없으면 이 리전의 모든 요청을 차단해야 합니다.

  • 거부 규칙에서 AU 리전의 요청과 일치하는 다음 표현식을 사용합니다.

    origin.region_code == 'AU'
    

또는 웹 애플리케이션을 AU 리전에서 사용할 수 있는 경우 다른 모든 리전의 요청을 차단해야 합니다.

  • 거부 규칙에서 AU 리전을 제외한 모든 리전의 요청과 일치하는 다음 표현식을 사용합니다.

    origin.region_code != 'AU'
    

리전 코드는 ISO 3166-1 alpha 2 코드를 기반으로 합니다. 경우에 따라 리전이 국가에 해당하지만 항상 그런 것은 아닙니다. 예를 들어 US 코드는 미국의 모든 주, 구역 1개, 외곽 지역 6개를 포함합니다.

특정 ASN의 트래픽 허용 또는 거부

특정 네트워크 제공업체에서 서비스를 제공받는 고객에 대해 웹 애플리케이션이 차단되어야 하는 경우 통신망 사업자의 ASN 번호를 사용하여 차단할 수 있습니다.

  • 거부 규칙에서 특정 ASN의 요청과 일치하는 다음 표현식을 사용합니다.

    origin.asn == 123
    

또는 특정 네트워크 제공업체를 이용하는 고객 웹 애플리케이션을 사용할 수 있는 경우 다른 모든 통신망 사업자의 요청을 차단해야 합니다.

  • 거부 규칙에서 허용할 다른 연산자를 제외한 다른 모든 네트워크 제공업체와 일치하는 다음 표현식을 사용합니다.

    origin.asn != 123
    

여러 표현식

규칙 하나에 여러 조건을 포함하려면 하위 표현식 여러 개를 결합합니다.

  • 다음 예시에서 AU 리전에 있는 1.2.3.0/24(예: 알파 테스터)의 요청은 다음 표현식과 일치합니다.

    origin.region_code == "AU" && inIpRange(origin.ip, '1.2.3.0/24')
    
  • 다음 표현식은 사용자 에이전트가 WordPress 문자열을 포함하는 1.2.3.4의 요청과 일치합니다.

    inIpRange(origin.ip, '1.2.3.4/32') &&
    has(request.headers['user-agent']) && request.headers['user-agent'].contains('WordPress')
    

정규 표현식과 일치하는 요청 URI의 트래픽 허용 또는 거부

  • 다음 표현식은 URI에 example_path 문자열이 포함된 요청과 일치합니다.

    request.path.matches('/example_path/')
    
  • 다음 표현식은 User-Agent 헤더 필드에 Chrome이 포함된 요청과 일치합니다.

    request.headers['user-agent'].matches('Chrome')
    
  • 다음 표현식은 wordpress가 포함되는 User-Agent 헤더에 대소문자를 구분하지 않는 일치를 보여줍니다. 이는 User-Agent:WordPress/605.1.15, User-Agent:wordPress, wordpress의 기타 변형과 일치합니다.

    request.headers['user-agent'].matches('(?i:wordpress)')
    

특정 Base64 디코딩 값이 포함된 트래픽 허용 또는 거부

  • 다음 표현식은 user-id 헤더의 Base64 디코딩 값이 myValue인 요청과 일치합니다.

    has(request.headers['user-id']) && request.headers['user-id'].base64Decode().contains('myValue')
    

특정 길이의 문자열 값이 포함된 트래픽 허용 또는 거부

  • 다음 표현식은 URL 길이가 10자를 초과하는 요청과 일치합니다.

    size(request.path) > 10
    
  • 다음 표현식은 헤더 x-data 길이가 1,024자 이상인 요청과 일치합니다.

    size(request.headers['x-data']) >= 1024
    

HTTP 본문에 content-length가 0인 트래픽 허용 또는 거부

  • 다음 표현식은 HTTP 본문에서 content-length가 0인 요청과 일치합니다.

    int(request.headers["content-length"]) == 0
    

특정 URL 인코딩 값이 포함된 트래픽 허용 또는 거부

  • 다음 표현식은 %3c가 포함된 쿠키 값이 있는 요청과 일치합니다.

    has(request.headers['cookie']) && request.headers['cookie'].urlDecode().contains('<')
    

유니코드 문자열의 특정 URL 인코딩 값이 포함된 트래픽 허용 또는 거부

  • 다음 표현식은 Match%2BValue 또는 Match%u002BValue에 해당하는 쿠키 값이 있는 요청과 일치합니다.

    has(request.headers['cookie']) && request.headers['cookie'].urlDecodeUni() == 'Match+Value'
    

UTF-8 텍스트의 특정 유니코드 문자열이 포함된 트래픽 허용 또는 거부

  • 다음 표현식은 ¬에 해당하는 쿠키 값이 있는 요청과 일치합니다.

    has(request.headers['cookie']) && request.headers['cookie'].utf8ToUnicode() == '%u00ac'
    

알려진 JA3 디지털 지문을 기반으로 트래픽 허용 또는 거부

  • 다음 표현식은 e7d705a3286e19ea42f587b344ee6865과 동일한 JA3 디지털 지문이 있는 요청과 일치합니다.

    origin.tls_ja3_fingerprint == 'e7d705a3286e19ea42f587b344ee6865'
    

JA3 디지털 지문 목록을 기반으로 트래픽 허용 또는 거부

  • 다음 표현식은 다음 JA3 디지털 지문과 동일한 JA3 디지털 지문이 있는 요청과 일치합니다.

    • e7d705a3286e19ea42f587b344ee6865
    • f8a5929f8949e846267b582072e35f84
    • 8f8b62163873a62234c14f15e7b88340
    origin.tls_ja3_fingerprint == 'e7d705a3286e19ea42f587b344ee6865' || origin.tls_ja3_fingerprint == 'f8a5929f8949e846267b582072e35f84' || origin.tls_ja3_fingerprint == '8f8b62163873a62234c14f15e7b88340'
    

사전 구성된 WAF 규칙

사전 구성된 WAF 규칙은 사전 구성된 정적 서명, 정규 표현식 또는 둘 다를 사용하여 HTTP POST 본문, HTTP 요청 헤더와 쿼리 매개변수를 일치시킵니다. 사용 가능한 사전 구성된 WAF 규칙은 OWASP Modsecurity core rule set 버전 3.3을 기반으로 합니다. Google Cloud Armor는 사전 구성된 몇 가지 WAF 규칙을 제공합니다. 사전 구성된 WAF 규칙의 전체 목록은 사전 구성된 Google Cloud Armor WAF 규칙 개요를 참조하세요.

사용 가능한 사전 구성된 WAF 규칙을 모두 나열하려면 사용 가능한 사전 구성된 WAF 규칙 나열을 참조하세요.

사전 구성된 WAF 규칙에 대한 자세한 내용은 사전 구성된 WAF 규칙을 사용하여 애플리케이션 레이어 공격 완화를 참조하세요.

사전 구성된 WAF 규칙 이름

사전 구성된 WAF 규칙 이름은 <attack category>-<ModSecurity CRS version>-<version field> 형식입니다. 공격 카테고리는 xss(교차 사이트 스크립팅) 또는 sqli(SQL 삽입)과 같은 보호하려는 공격 유형을 지정합니다.

지원되는 버전 필드는 stablecanary입니다. 규칙에 대한 추가와 수정은 canary 버전에서 먼저 출시됩니다. 추가와 수정이 안전하고 안정적인 것으로 간주되면 stable 버전으로 승격됩니다.

사전 구성된 WAF 규칙 구성원 ID

사전 구성된 WAF 규칙에는 각각 서명이 있는 여러 표현식이 포함되어 있습니다. 예를 들어 사전 구성된 WAF 규칙 xss-v33-stable에는 버전 3.3의 규칙 ID id941100에 해당하는 owasp-crs-v030301-id941100-xss라는 표현식이 포함되어 있습니다. 서명을 사용하여 특정 표현식이 사용되지 않도록 제외할 수 있습니다. 이는 특정 표현식이 지속적으로 거짓양성을 트리거하는 경우에 유용합니다. 자세한 내용은 거짓양성 문제 해결 정보를 참조하세요.

핵심 규칙 세트와 다양한 민감도 수준에서 조정하는 방법에 대한 자세한 내용은 Google Cloud Armor WAF 규칙 조정을 참조하세요.

사전 구성된 WAF 규칙 연산자

표현식 설명
evaluatePreconfiguredWaf(string, MAP<string, dyn>) 지정된 WAF 규칙 세트 내 WAF 서명 중 하나가 true를 반환하면 true를 반환합니다. 첫 번째 인수는 WAF 규칙 집합의 이름입니다(예: xss-v33-stable). 두 번째 인수(선택사항)는 키가 문자열이고 키에 따라 값이 동적으로 입력되는 맵입니다. 이 인수의 목적은 평가되는 WAF 서명을 미세 조정하는 것입니다. 허용되는 키에는 다음이 포함됩니다.
  • 'sensitivity': ModSecurity Core Rule Set paranoia 수준에 해당되며, 1부터 4까지 4개의 레벨이 있습니다. 이 값은 유효 범위가 0~4인 정수입니다. 0은 'opt_in_rule_ids'와 함께 사용할 경우 유효한 값으로 예약됩니다(이후에 설명). x(x >= 1)의 민감도를 지정하면 1에서 x까지의 민감도 값을 가진 모든 연결된 WAF 서명이 평가됩니다. 생략하면 4가 민감도 값으로 사용됩니다.
  • 'opt_out_rule_ids': 평가에서 선택 해제할 WAF 서명(규칙 ID로 표시됨)으로, 기본 세트는 민감도 값에 의해 결정됩니다. 값은 문자열 목록입니다. 허용되는 최대 규칙 ID 수는 128개입니다.
  • 'opt_in_rule_ids': 평가를 위해 선택할 WAF 서명(규칙 ID로 표시)으로, 기본 세트가 비어 있습니다. 값은 문자열 목록입니다. 허용되는 최대 규칙 ID 수는 128개입니다. 이 키를 사용하는 경우 0의 '민감도'를 지정해야 합니다.

'opt_out_rule_ids' 및 'opt_in_rule_ids' 키는 상호 배타적입니다. 기존 규칙 집합에 나중에 추가되는 새 WAF 서명을 검토하고 수동으로 사용 설정하려면 'opt_in_rule_ids'를 사용할 수 있습니다.

evaluatePreconfiguredExpr(string, LIST)

지정된 사전 구성된 WAF 규칙 내 표현식 중 하나가 true를 반환하면 true를 반환합니다.

첫 번째 인수는 사전 구성된 WAF 규칙의 이름입니다(예: xss-stable). 두 번째 인수(선택사항)는 평가에서 제외해야 하는 쉼표로 구분된 ID의 문자열 목록입니다. 제외 목록은 지정된 사전 구성된 WAF 규칙 구성원이 거짓양성을 트리거하는 경우에 유용합니다.

사전 구성된 WAF 규칙의 예

  • 다음 표현식은 사전 구성된 WAF 규칙 xss-v33-stable을 사용하여 XSS 공격을 완화합니다.

    evaluatePreconfiguredExpr('xss-v33-stable')
    
  • 다음 표현식은 구성원 ID 941100941110을 제외하고 xss-v33-stable 사전 구성된 WAF 규칙의 모든 표현식을 사용합니다.

    evaluatePreconfiguredExpr('xss-v33-stable', ['owasp-crs-v030301-id941100-xss',
    'owasp-crs-v030301-id941110-xss'])
    
  • 다음 표현식은 사전 구성된 WAF 규칙을 사용하여 198.51.100.0/24 IP 주소 범위에서 SQLi 공격을 완화합니다.

    inIpRange(origin.ip, '198.51.100.0/24') && evaluatePreconfiguredExpr('sqli-v33-stable')
    

다음 단계