Cloud Armor 보안 정책 규칙 만들기 및 보기

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

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

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

이 페이지에서는 보안 정책 규칙을 만들고 보는 방법을 설명하고 고급 일치 조건에서 표현식을 작성하는 데 사용하는 Cloud Armor 커스텀 규칙 언어에 대한 참조를 제공합니다. Cloud Armor 커스텀 규칙 언어는 Common Expression Language(CEL)의 하위 집합입니다.

Cloud Armor 커스텀 규칙 언어로 작성된 표현식에는 다음 두 가지 구성요소가 필요합니다.

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

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

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

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

보안 정책 규칙 만들기

이 섹션의 단계에 따라 Cloud Armor 보안 정책에 규칙을 추가합니다.

콘솔

  1. Google Cloud 콘솔에서 Cloud Armor 정책 페이지로 이동합니다.

    Cloud Armor 정책으로 이동

  2. 보안 정책 이름을 클릭하여 정책 세부정보 페이지를 연 다음 규칙 탭을 클릭합니다.

  3. 규칙 추가를 클릭합니다.

  4. 원하는 경우 규칙 설명을 입력합니다.

  5. 모드를 선택합니다.

    • 기본 모드: IP 주소 또는 범위를 기준으로 트래픽을 허용하거나 거부합니다.
    • 고급 모드: 규칙 표현식을 기준으로 트래픽을 허용하거나 거부합니다.
  6. 일치 필드에서 규칙이 적용되는 조건을 지정합니다.

    • 기본 모드: 규칙과 일치하는 IP 주소 범위를 1개에서 10개까지 입력합니다. IP 주소 범위는 최대 10개까지 추가할 수 있습니다. 한도는 Cloud Armor 할당량 및 한도를 참고하세요.

    • 고급 모드:

      • 일치 조건 작성 도구(프리뷰): 시각적 작성 도구를 사용하여 원시 CEL 코드를 작성하지 않고 표현식을 만듭니다. 조건을 결합 및 그룹화하고 문자열 변환을 적용합니다. 일치 조건 작성 도구 사용을 참고하세요.
      • 일치 조건 편집기: 들어오는 요청을 평가할 표현식을 입력합니다. 자세한 내용은 작업 및 속성을 참조하세요.
  7. 작업 목록에서 허용 또는 거부를 선택합니다.

  8. 거부 규칙을 구성하는 경우 응답 코드 목록에서 응답 코드를 선택합니다.

  9. 규칙에 대한 미리보기 모드를 사용 설정하려면 사용 설정을 선택합니다.

  10. 우선순위 필드에 0에서 2,147,483,646 사이의 정수를 입력합니다. Cloud Armor는 0(최고)에서 2,147,483,647(최저) 사이의 우선순위 순서로 규칙을 평가합니다. 기본 규칙의 우선순위는 2,147,483,647입니다.

  11. 추가를 클릭합니다.

gcloud

gcloud compute security-policies rules create PRIORITY 명령어를 사용합니다. PRIORITY를 정책에 있는 규칙의 우선순위로 바꿉니다.

gcloud compute security-policies rules create PRIORITY \
    --security-policy POLICY_NAME \
    --description DESCRIPTION \
    --src-ip-ranges IP_RANGES | --expression EXPRESSION \
    --action=[ allow | deny-403 | deny-404 | deny-502 ] \
    --preview

예를 들어 다음 명령어는 IP 주소 범위 192.0.2.0/24 및 198.51.100.0/24에서 트래픽을 차단하는 우선순위가 1, 000인 규칙을 추가합니다.

gcloud compute security-policies rules create 1000 \
    --security-policy my-policy \
    --description "block traffic from 192.0.2.0/24 and 198.51.100.0/24" \
    --src-ip-ranges "192.0.2.0/24","198.51.100.0/24" \
    --action "deny-403"

--expression 플래그를 사용하여 조건을 지정합니다. 다음 명령어는 IP 주소 1.2.3.4에서 들어오는 트래픽을 허용하고 User-Agent 헤더의 example 문자열을 포함하는 규칙을 추가합니다.

gcloud compute security-policies rules create 1000 \
    --security-policy my-policy \
    --expression "inIpRange(origin.ip, '1.2.3.4/32') && has(request.headers['user-agent']) && request.headers['user-agent'].contains('example')" \
    --action allow \
    --description "Block User-Agent 'example'"

다음 명령어는 요청 쿠키에 특정 값이 포함되면 요청을 차단하는 규칙을 추가합니다.

gcloud compute security-policies rules create 1000 \
    --security-policy my-policy \
    --expression "has(request.headers['cookie']) && request.headers['cookie'].contains('80=SomeValue')" \
    --action deny-403 \
    --description "Cookie Block"

다음 명령어는 리전 AU의 요청을 차단하는 규칙을 추가합니다.

gcloud compute security-policies rules create 1000 \
    --security-policy my-policy \
    --expression "origin.region_code == 'AU'" \
    --action deny-403 \
    --description "AU block"

다음 명령어는 지정된 IP 범위에 없는 AU 리전의 요청을 차단하는 규칙을 추가합니다.

gcloud compute security-policies rules create 1000 \
    --security-policy my-policy \
    --expression "origin.region_code == \"AU\" && !inIpRange(origin.ip, '1.2.3.0/24')" \
    --action deny-403 \
    --description "country and IP block"

다음 명령어는 정규 표현식과 일치하는 URI가 있는 요청을 차단하는 규칙을 추가합니다.

gcloud compute security-policies rules create 1000 \
    --security-policy my-policy \
    --expression "request.path.matches('/example_path/')" \
    --action deny-502 \
    --description "regex block"

다음 명령어는 user-id 헤더의 Base64 디코딩 값에 특정 값이 포함된 경우 요청을 차단하는 규칙을 추가합니다.

gcloud compute security-policies rules create 1000 \
    --security-policy my-policy \
    --expression "has(request.headers['user-id']) && request.headers['user-id'].base64Decode().contains('myValue')" \
    --action deny-403 \
    --description "country and IP block"

다음 명령어는 OWASP 핵심 규칙 집합(CRS) 4.22의 사전 구성된 표현식 세트를 사용하여 SQL 삽입(SQLi) 공격을 완화하는 규칙을 추가합니다.

gcloud compute security-policies rules create 1000 \
    --security-policy my-policy \
    --expression "evaluatePreconfiguredWaf('sqli-v422-stable')" \
    --action deny-403

일치 조건 작성 도구 사용

일치 조건 작성 도구는 Google Cloud 콘솔의 시각적 인터페이스로, Common Expression Language(CEL) 코드를 작성하지 않고도 복잡한 Cloud Armor 규칙 표현식을 만들 수 있습니다. 코드를 작성하는 대신 빌더의 구조화된 UI를 사용하여 조건과 그룹 로직을 결합할 수 있으므로 문법 오류를 방지하고 규칙 구조를 더 잘 시각화할 수 있습니다. 빌더는 최대 5개 수준의 표현식까지 플랫 목록과 중첩 로직을 지원합니다. 트래픽을 라우팅하기 전에 특정 요청 속성을 검사해야 할 수 있는 멀티 클라우드 백엔드 또는 하이브리드 배포를 보호하는 데 도움이 되는 규칙을 구성할 때 이 도구를 사용하세요.

일치 조건 작성 도구의 기능

일치 조건 작성 도구에는 다음 기능이 포함됩니다.

  • 로직 및 중첩: AND 및 OR 연산자를 사용하여 여러 조건을 결합합니다. 빌더는 최대 5개의 표현식을 그룹화하고 중첩할 수 있습니다.
  • 문자열 변환: 문자열 기반 속성(예: request.path 또는 request.headers)의 경우 평가 전에 변환을 적용하여 데이터를 정규화합니다. 지원되는 변환은 다음과 같습니다.
    • 소문자 및 대문자
    • Base64 디코딩
    • URL 디코딩 및 URL 디코딩(유니코드)
    • UTF-8을 유니코드로 변환
  • 양방향 파싱: 시각적 일치 조건 작성 도구와 원시 텍스트 일치 조건 편집기 간에 전환합니다. UI는 원시 CEL 코드를 시각적 블록으로 자동 파싱합니다.
  • 함수 지원: 빌더는 사전 구성된 WAF 규칙, 주소 그룹, 위협 인텔리전스와 같은 함수 기반 표현식에 대한 UI 컨트롤을 제공합니다.

제한사항

일치 조건 작성 도구는 고급 규칙 생성을 위한 기본 인터페이스입니다. 표현식에 지원되지 않는 로직(예: 알 수 없는 매크로)이 포함된 경우 빌더가 사용 중지됩니다. 이러한 경우 일치 조건 편집기의 원시 텍스트를 사용하여 규칙을 수정합니다.

또한 빌더에서 특정 표현식을 사용할 수 있는지 여부는 프로젝트의 Google Cloud Armor Enterprise 등급과 보안 정책 유형에 따라 다릅니다.

샘플 표현식

다음은 샘플 표현식입니다. 지원되는 작업 및 속성에 대한 자세한 내용은 작업 및 속성을 참조하세요.

규칙이나 표현식에서 ISO 3166-1 alpha-2 국가 또는 리전 코드를 사용하는 경우 Cloud Armor는 각 코드를 독립적으로 처리합니다. Cloud Armor 규칙과 표현식은 이러한 코드를 사용하여 요청을 허용하거나 거부합니다.

  • 다음 표현식은 User-Agent 헤더에 example 문자열이 포함된 IP 주소 1.2.3.4의 요청과 일치합니다.

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

    또는 origin.user_ip 속성을 사용하여 커스텀 클라이언트 IP 주소 헤더의 IP 주소 범위에 일치시킵니다.

    inIpRange(origin.user_ip, '1.2.3.4/32') && has(request.headers['user-agent']) && request.headers['user-agent'].contains('example')
    
  • 다음 표현식은 특정 값을 가진 쿠키가 있는 요청과 일치합니다.

    has(request.headers['cookie']) && request.headers['cookie'].contains('cookie_name=cookie_value')
    
  • 다음 표현식은 AU 리전의 요청과 일치합니다.

    origin.region_code == 'AU'
    
  • 다음 표현식은 지정된 IP 범위가 아닌 AU 리전의 요청과 일치합니다.

    origin.region_code == "AU" && !inIpRange(origin.ip, '1.2.3.0/24')
    
  • URI가 정규 표현식과 일치하면 다음 표현식은 번호가 지정된 변수 경로를 사용한 특정 파일에 대한 요청과 일치합니다.

    request.path.matches('/path/[0-9]+/target_file.html')
    
  • 다음 표현식은 Base64로 디코딩된 user-id 헤더 값에 특정 값이 포함되면 요청과 일치합니다.

    has(request.headers['user-id']) && request.headers['user-id'].base64Decode().contains('myValue')
    
  • 다음 표현식은 OWASP CRS 4.22 규칙 집합의 사전 구성된 표현식 집합을 사용하여 SQLi 공격과 일치시킵니다.

    evaluatePreconfiguredWaf('sqli-v422-stable')
    

경로 순회 및 정규화

경로 기반 규칙에서 콘텐츠를 정규화하여 경로 순회 및 인코딩 규칙을 관리하고 대문자 또는 콘텐츠별 인코딩을 방지하는 일반화된 규칙을 만듭니다.

startsWith, endsWith 또는 contains를 사용하여 request.path에서 매칭할 규칙을 작성할 때는 lower 및 urlDecode를 사용해 매칭하기 전에 경로를 정규화합니다. 이렇게 하면 URL 인코딩 또는 대소문자 변형을 사용하는 우회를 방지할 수 있습니다.

예를 들어 /admin 디렉터리에 대한 액세스를 차단하려면 다음 표현식을 사용합니다.

request.path.lower().urlDecode().startsWith('/admin')

이 규칙은 /admin, /Admin, /a%64min 및 기타 변형에 대한 요청을 차단합니다.

matches를 사용하여 request.path에 매칭하는 규칙을 작성할 때는 정규 표현식에서 백슬래시 문자(\)를 고려합니다.

예를 들어 /admin 디렉터리에 대한 액세스를 차단하려면 다음 표현식을 사용하여 백슬래시 문자(\)를 사용하는 우회를 차단합니다.

request.path.matches(r'^/\\*admin')

이를 urlDecode와 결합하여 URL 인코딩과 백슬래시 문자(\) 우회를 모두 처리합니다.

request.path.urlDecode().matches(r'^/\\*admin')

보안 정책 규칙 보기

다음 섹션에서는 보안 정책에 구성된 규칙을 나열하고 사용 가능한 사전 구성된 WAF 규칙을 보는 방법을 설명합니다.

보안 정책의 규칙 나열

이 섹션의 단계에 따라 Cloud Armor 보안 정책의 규칙을 나열합니다.

콘솔

  1. Google Cloud 콘솔에서 Cloud Armor 정책 페이지로 이동합니다.

    Cloud Armor 정책으로 이동

  2. 특정 보안 정책의 이름을 클릭합니다. 정책 세부정보 페이지의 규칙 탭에 정책 규칙이 표시됩니다.

gcloud

다음 gcloud 명령어를 사용하여 보안 정책의 모든 규칙을 나열합니다.

gcloud compute security-policies describe NAME

다음 gcloud 명령어를 사용하여 지정된 리전의 보안 정책 하나의 모든 규칙을 정책 설명과 함께 나열합니다.

gcloud compute security-policies describe NAME \
  --region REGION

다음 gcloud 명령어를 사용하여 규칙을 설명합니다.

gcloud compute security-policies rules describe PRIORITY \
    --security-policy POLICY_NAME

예를 들어 다음 명령어는 보안 정책 my-policy에서 우선순위가 1, 000인 규칙을 설명합니다.

gcloud compute security-policies rules describe 1000 \
    --security-policy my-policy

출력:

action: deny(403)
description: block traffic from 192.0.2.0/24 and 198.51.100.0/24
kind: compute#securityPolicyRule
match:
  srcIpRanges:
  - '192.0.2.0/24'
  - '198.51.100.0/24'
preview: false
priority: 1000

자세한 내용은 gcloud compute security-policies describe를 참조하세요.

사용 가능한 사전 구성된 규칙 나열

Cloud Armor는 직접 구성하는 규칙 외에도 보안 정책에 사용할 수 있는 사전 구성된 규칙을 제공합니다. 사전 구성된 규칙을 나열하여 Cloud Armor에서 제공하는 OWASP 핵심 규칙 세트(CRS)와 같은 사전 정의된 애플리케이션 보호 규칙과 서명을 볼 수 있습니다. 이러한 규칙에는 Cloud Armor가 들어오는 요청을 평가하는 기본 제공 서명이 포함되어 있습니다. 커스텀 규칙 언어를 사용하여 이러한 사전 구성된 규칙을 새로운 규칙이나 기존 규칙에 추가합니다. 가능하면 최신 CRS 규칙 버전을 사용하는 것이 좋습니다.

gcloud

  1. gcloud compute security-policies list-preconfigured-expression-sets 명령어를 실행합니다.

    gcloud compute security-policies list-preconfigured-expression-sets
    

    다음 예시에서는 이 명령어의 출력 형식을 보여줍니다.

    EXPRESSION_SET
    expression-set-1
       RULE_ID                SENSITIVITY
       expression-set-1-id-1  sensitivity-value-1
       expression-set-1-id-2  sensitivity-value-2
    expression-set-2
       alias-1
       RULE_ID                SENSITIVITY
       expression-set-2-id-1  sensitivity-value-1
       expression-set-2-id-2  sensitivity-value-2
    

    다음 예시에는 이 명령어의 실제 출력 샘플이 포함되어 있습니다. 실제 출력에는 Cloud Armor WAF 규칙 조정에 나와 있는 모든 규칙이 포함됩니다.

    gcloud compute security-policies list-preconfigured-expression-sets
    
    EXPRESSION_SET
    sqli-canary
        RULE_ID                          SENSITIVITY
        owasp-crs-v042200-id942120-sqli  2
        …
    xss-canary
        RULE_ID                         SENSITIVITY
        owasp-crs-v042200-id941110-xss  1
        owasp-crs-v042200-id941120-xss  2
    …
    sourceiplist-fastly
    sourceiplist-cloudflare
    sourceiplist-imperva
    

작업

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

작업 표현식 설명
형평성 x == y x가 y와 같으면 true를 반환합니다.
등식, 문자열 리터럴 x == "foo" x가 주어진 상수 문자열 리터럴과 같으면 true를 반환합니다.
등식, 원시 문자열 리터럴 x == R"fo'o" x가 이스케이프 문자 시퀀스를 해석하지 않는 지정된 원시 문자열 리터럴과 같으면 true를 반환합니다. 원시 문자열 리터럴은 이스케이프 시퀀스 문자를 사용해야 하는 문자열을 표현하는 데 편리합니다.
논리 부정 !x 불리언 값 x가 false이면 true를 반환하고 불리언 값 x가 true이면 false를 반환합니다.
같지 않음 x != y x가 y와 같지 않으면 true를 반환합니다.
연결 x + y 연결된 문자열 xy를 반환합니다.
논리곱 x && y x와 y가 모두 true이면 true를 반환합니다.
논리합 x || y x, y 또는 둘 다 true이면 true를 반환합니다.
하위 문자열 포함 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 옵션을 통해 컴파일됩니다.
범위 내 IP 주소 inIpRange(x, y) IP 주소 x가 IP 범위 y 내에 포함되어 있으면 true를 반환합니다.
소문자 x.lower() 문자열 x의 소문자 값을 반환합니다.
대문자 x.upper() 문자열 x의 대문자 값을 반환합니다.
Base64로 디코딩된 값 x.base64Decode() base64로 디코딩된 x 값을 반환합니다. 밑줄(_)과 하이픈(-)은 먼저 각각 슬래시(/)와 더하기 기호(+)로 바뀝니다. x가 유효한 base64 값이 아니면 ""(빈 문자열)를 반환합니다.
키 맵 값 m['k'] k를 사용할 수 있으면 문자열 간 맵 m에서 키 k의 값을 반환하고 그렇지 않으면 오류를 반환합니다. 먼저 "has(m['k'])==true"를 사용하여 가용성을 확인하는 것이 좋습니다.
지도에서 키 사용 가능 여부 확인 has(m['k']) 맵 m에서 키 k를 사용할 수 있으면 true를 반환합니다.
정수로 변환 int(x) x의 문자열 결과를 int 유형으로 변환합니다. 그러면 > 와 <= 같은 표준 산술 연산자를 사용하여 정수 비교를 수행하는 데 사용할 수 있으며 정수여야 하는 값에만 작동합니다.
길이 size(x) 문자열 x의 길이를 반환합니다.
URL 디코딩 x.urlDecode() URL로 디코딩된 x 값을 반환합니다. %## 형식의 문자 시퀀스는 ASCII가 아닌 문자 시퀀스로 바뀌고 +은 공백으로 바뀝니다. 잘못된 인코딩은 그대로 반환됩니다.
URL 디코딩(유니코드) x.urlDecodeUni() URL로 디코딩된 x 값을 반환합니다. 이렇게 하면 urlDecode() 외에도 %u### 형식의 유니코드 문자 시퀀스가 처리됩니다. 잘못된 인코딩은 그대로 반환됩니다.
utf8을 유니코드로 변환 x.utf8ToUnicode() UTF-8로 인코딩된 x의 x 유니코드 표현식을 반환합니다.
존재 m.exists(k, expr) m 맵의 항목 중 하나 이상이 expr를 충족하면 true를 반환합니다. 여기서 k는 각 맵 항목의 키를 나타냅니다.
1개 존재 m.exists_one(k, expr) 맵 m의 항목 중 정확히 하나가 expr를 충족하는 경우 true를 반환합니다. 여기서 k는 각 맵 항목의 키를 나타냅니다.
전체 m.all(k, expr) 맵 m의 모든 항목이 expr를 충족하면 true를 반환합니다. 여기서 k는 각 맵 항목의 키를 나타냅니다.
필터 m.filter(k, expr) 항목이 expr를 충족하는 맵 m의 항목만 포함하는 맵을 반환합니다. 여기서 k는 각 맵 항목의 키를 나타냅니다.
지도 m.map(k, expr) m 맵의 각 키에 대해 expr를 평가한 결과가 포함된 목록을 반환합니다. 여기서 k는 각 맵 항목의 키를 나타냅니다.

속성

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

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

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

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

has()를 사용하여 가용성을 확인합니다(예: has(request.headers['header-key']) && request.headers['header-key'] != 'header-value').

맵을 반복하여 키와 값을 모두 확인할 수 있습니다. 하지만 request.headers에서 맵 반복 연산자(exists(), exists_one(), all(), filter(), map())는 동일한 표현식에서 request.body 또는 request.params와 조합해서만 사용할 수 있습니다(예: request.body && request.headers.exists(k, k.lower().startsWith('header-prefix'))).

request.body 문자열 요청 본문을 원시 문자열로 나타냅니다. 모든 Content-Type의 데이터를 나타낼 수 있습니다. 자동 파싱 없이 콘텐츠를 문자열로 저장합니다.
request.params 지도 URL에 추가되거나 요청 본문에 포함된 키-값 쌍의 맵입니다.
URI 요청: name1=value1&name2=value2
Content-Type: application/json가 있는 JSON 요청 본문:
{ "username": "johndoe", "email": "johndoe@example.com" }
Content-Type: application/graphql가 있는 GraphQL POST 요청 본문:
{ Username: "exampleUser", query: "/* other fields */" }
Content-Type: application/x-www-form-urlencoded가 있는 양식 POST 요청 본문:
"username=exampleUser&email=johndoe%40example.com"
request.method 문자열 HTTP 요청 메서드입니다.
request.path 문자열 요청한 HTTP URL 경로입니다. request.path에 매칭하는 규칙을 작성할 때는 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 국가 또는 리전 코드를 사용하는 규칙이나 표현식을 만들면 Cloud Armor는 각 코드를 독립적으로 처리합니다. Cloud Armor 규칙과 표현식은 리전 코드를 명시적으로 사용하여 요청을 허용하거나 거부합니다.
origin.asn 정수 클라이언트 IP 주소와 연결된 자율 시스템 번호(ASN)입니다. 전역적으로 고유한 ASN은 클라이언트 IP 주소가 포함된 IP 주소 프리픽스를 지원하는 네트워크 연산자를 기반으로 결정됩니다.

표현식 예시

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

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'] != ""
    

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

요청의 Host 헤더 값을 기준으로 트래픽을 허용하거나 거부할 수 있습니다.

  • 다음 표현식은 ==를 사용하여 특정 URL에 대한 요청과 일치합니다.

    request.headers['host'].lower() == 'test.example.com'
    
  • 다음 표현식은 endsWith를 사용하여 특정 URL에 대한 요청과 일치합니다.

    request.headers['host'].lower().endsWith('.example.com')
    
  • 다음 표현식은 contains를 사용하여 특정 URL에 대한 요청과 일치합니다.

    request.headers['host'].lower().contains('test.example.com')
    
  • 다음 표현식은 contains를 사용하여 여러 도메인에 대한 요청과 일치합니다.

    request.headers['host'].lower().contains('test.example.com') || request.headers['host'].lower().contains('test22.example.com')
    
  • 다음 표현식은 matches를 사용하여 도메인 및 하위 도메인에 대한 요청과 일치합니다.

    request.headers['host'].matches('(?i:(?:sub\.)?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'
    

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

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

    origin.tls_ja4_fingerprint == 't13d1516h2_8daaf6152771_b186095e22b6'
    

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

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

    • t00d0000h0_000000000000_000000000000
    • t13d1516h2_8daaf6152771_b186095e22b6
    origin.tls_ja4_fingerprint == 't00d0000h0_000000000000_000000000000' || origin.tls_ja4_fingerprint == 't13d1516h2_8daaf6152771_b186095e22b6'
    

요청 본문 콘텐츠를 기준으로 트래픽 허용 또는 거부

  • 다음 표현식은 요청 본문에 malicious-value가 포함된 POST 요청과 일치합니다.

    request.method == 'POST' && request.body.contains('malicious-value')
    
  • 다음 표현식은 <!DOCTYPE html>로 시작하는 요청과 일치합니다.

    request.body.startsWith('<!DOCTYPE html>')
    
  • 다음 표현식은 본문이 정규 표현식 \w+@\w+.com과 일치하는 요청과 일치합니다.

    request.body.matches('\w+@\w+.com')
    

요청 매개변수를 기준으로 트래픽 허용 또는 거부

  • 다음 표현식은 category라는 매개변수가 포함되지 않은 요청과 일치합니다.

    !has(request.params.category)
    
  • 다음 표현식은 category 매개변수가 electronics인 요청과 일치합니다.

    request.params.category == 'electronics'
    
  • 다음 표현식은 모든 파라미터 값이 비어 있지 않은 요청과 일치합니다.

    request.params.all(k, request.params[k] != '')
    
  • 다음 표현식은 매개변수에 admin 문자열이 포함된 요청과 일치합니다.

    request.params.exists(k, request.params[k].contains('admin'))
    
  • 다음 표현식은 정확히 하나의 매개변수 이름에 admin가 포함된 요청과 일치합니다.

    request.params.exists_one(k, k.contains('admin'))
    
  • 다음 표현식은 하나 이상의 매개변수 이름에 id가 포함된 요청과 일치합니다.

    size(request.params.filter(k, k.contains('id'))) > 0
    
  • 다음 표현식은 파라미터 값에 admin 문자열이 포함된 요청과 일치합니다.

    request.params.map(k, request.params[k]).contains('admin')
    

요청 본문의 정형 데이터를 기준으로 트래픽 허용 또는 거부

  • 다음 표현식은 JSON 요청 본문의 password 필드에 123가 포함된 요청과 일치합니다.

    has(request.params.password) && request.params.password.contains('123')
    
  • 다음 표현식은 양식 데이터의 city 필드가 NewYork인 요청과 일치합니다.

    has(request.params.city) && request.params.city == 'NewYork'
    
  • 다음 표현식은 중첩된 newsletter 필드가 true인 요청과 일치합니다.

    has(request.params.preferences) && has(request.params.preferences.newsletter) && request.params.preferences.newsletter == true
    
  • 다음 표현식은 friends 배열의 첫 번째 요소의 name 필드가 johndoe인 요청과 일치합니다.

    request.params['friends'][0]['name'] == 'johndoe'
    

사전 구성된 WAF 규칙

사전 구성된 WAF 규칙은 사전 구성된 정적 서명, 정규 표현식 또는 둘 다를 사용하여 HTTP 요청 본문, HTTP 요청 헤더 및 쿼리 파라미터를 일치시킵니다. 사용 가능한 사전 구성된 WAF 규칙은 OWASP 핵심 규칙 집합 4.22를 기반으로 합니다. Cloud Armor는 사전 구성된 몇 가지 WAF 규칙을 제공합니다. 사전 구성된 WAF 규칙의 전체 목록은 Cloud Armor 사전 구성된 WAF 규칙 개요를 참조하세요.

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

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

사전 구성된 WAF 규칙 이름

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

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

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

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

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

사전 구성된 WAF 규칙 연산자

표현식 설명
evaluatePreconfiguredWaf(string, MAP<string, dyn>) 지정된 WAF 규칙 집합 내 WAF 서명 중 하나가 true를 반환하면 true를 반환합니다. 첫 번째 인수는 xss-v422-stable 등의 WAF 규칙 집합의 이름입니다. 두 번째 인수(선택사항)는 키가 문자열이고 값은 키에 따라 동적으로 입력되는 맵입니다. 이 인수의 목적은 평가되는 WAF 서명을 미세 조정하는 것입니다. 허용되는 키에는 다음이 포함됩니다.
  • sensitivity: OWASP 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의 sensitivity를 지정해야 합니다.

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

evaluatePreconfiguredWaf(string, LIST)

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

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

사전 구성된 WAF 규칙의 예

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

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

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

    inIpRange(origin.ip, '198.51.100.0/24') && evaluatePreconfiguredWaf('sqli-v422-stable')
    
  • 다음 표현식은 사전 구성된 WAF 규칙 xss-v422-stable을 사용하여 /login/api/로 시작하는 경로를 제외하고 example.com에 대한 요청의 XSS 공격을 완화합니다.

    request.headers['host'].lower() == 'example.com' && !request.path.startswith('/login/api/') && evaluatePreconfiguredWaf('xss-v422-stable')
    

기타 연산자

표현식 설명
evaluateThreatIntelligence(string)
evaluateThreatIntelligence(string, LIST)
evaluateThreatIntelligence(string, string, LIST)

명시적으로 제외 목록으로 제외된 경우를 제외하고 클라이언트 IP 주소가 지정된 IP 목록의 IP 범위와 일치하면 true를 반환합니다.

첫 번째 인수는 Google Threat Intelligence 피드 이름입니다(예: iplist-known-malicious-ips). 두 번째 인수가 문자열(선택사항)인 경우 IP 주소가 추출되는 위치를 결정하며 origin.ip, origin.user_ip 또는 특정 헤더 이름일 수 있습니다. 두 번째 또는 세 번째 인수(선택사항)가 쉼표로 구분된 문자열 목록인 경우 각 문자열은 평가에서 제외되는 IP 주소 또는 CIDR 범위입니다. 제외 목록은 피드에 오탐을 트리거하는 IP 주소가 포함된 경우에 유용합니다.

evaluateAddressGroup(string, string)
evaluateAddressGroup(string, string, LIST)

evaluateOrganizationAddressGroup(string, string)
evaluateOrganizationAddressGroup(string, string, LIST)

명시적으로 제외 목록으로 제외된 경우를 제외하고 클라이언트 IP 주소가 지정된 주소 그룹의 IP 범위와 일치하면 true를 반환합니다.

첫 번째 인수는 주소 그룹 이름입니다. 두 번째 인수는 IP 주소가 추출되는 위치를 결정하며 origin.ip, origin.user_ip 또는 특정 헤더 이름일 수 있습니다. 세 번째 인수(선택사항)는 평가에서 제외될 쉼표로 구분된 문자열 목록으로, 각 문자열은 IP 주소 또는 CIDR 범위입니다. 제외 목록은 주소 그룹에 오탐을 트리거하는 IP 주소가 포함된 경우에 유용합니다.

evaluateAdaptiveProtection(string)

요청이 Google Cloud Armor Adaptive Protection에 의해 생성된 공격 서명과 일치하는 경우 true를 반환합니다.

인수는 공격이 감지될 때 Adaptive Protection에 의해 생성된 특정 알림의 ID입니다.

evaluateAdaptiveProtectionAutoDeploy()

Adaptive Protection에 의해 감지된 진행 중인 공격의 공격 서명과 일치하는 집중 공격자 IP 주소의 요청이면 true를 반환합니다.

예시

  • 다음 표현식은 알려진 악성 IP 목록으로부터 보호하기 위해 Google Threat Intelligence iplist-known-malicious-ips 피드에 대한 수신 요청과 일치합니다.

    evaluateThreatIntelligence('iplist-known-malicious-ips')
    
  • 다음 표현식은 203.0.113.0/24의 IP를 제외한 알려진 악성 IP 목록으로부터 보호하기 위해 Google Threat Intelligence iplist-known-malicious-ips 피드에 대한 수신 요청과 일치합니다.

    evaluateThreatIntelligence('iplist-known-malicious-ips', ['203.0.113.0/24'])
    
  • 다음 표현식은 my-own-list-of-bad-ips라는 주소 그룹에 대한 사용자 IP의 커스텀 요청 헤더와 일치합니다.

    evaluateAddressGroup('my-own-list-of-bad-ips', origin.user_ip)
    

다음 단계