Cloudflare Page Shield の Code change alert をテストする

# Cloudflare Page Shield
- [Cloudflare Page Shield · Cloudflare Page Shield docs](https://developers.cloudflare.com/page-shield/)

Web 通信を Cloudflare 経由にすることで、Cloudflare が [Content Security Policy レスポンスヘッダ](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) や [Content-Security-Policy-Report-Only レスポンスヘッダ](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only) を付与し、ページ内のスクリプトやコネクションを監視したり、AllowList で運用できる製品です。

![Customer facing - Page Shield customer facing pitch 日本語.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/5f7d058d-3a88-b665-de95-aea73e2ee9eb.png)

こうした機能は、以下のような Magecart Attack に対して有効な対策のひとつです。

- [Detecting Magecart-Style attacks with Page Shield](https://blog.cloudflare.com/detecting-magecart-style-attacks-for-pageshield/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/6867e81d-906e-8ca1-3f07-0f9b9cc82fa1.png)

# Code change alert
今回はこの機能を検証します。
サイトが使用する JavaScript に意味のある変更があった場合、アラートを受信します。

[Code change alert · Cloudflare Page Shield docs](https://developers.cloudflare.com/page-shield/reference/alerts/#code-change-alert)
> Available as a paid add-on for Cloudflare customers on an Enterprise plan.
Page Shield New Code Change Detection Alert: Triggered daily by any changed JavaScript dependencies detected in your pages.

# サンプルスクリプト
以下のスクリプトを使います。

- [custom.js](https://www.sweatybetty.com/on/demandware.static/-/Library-Sites-sweatybettylibrary/en_US/v1574703272172/js/custom.js)
    - Hash = `a991b04c6a5b3f800629782e47491ea6581b11df683c17e1df54510d15114027`

ダウンロードは以下のコマンドで実行できます。

```shell:
sudo curl -s https://www.sweatybetty.com/on/demandware.static/-/Library-Sites-sweatybettylibrary/en_US/v1574703272172/js/custom.js \
-o /var/www/html/js/custom.js
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/d33fbbea-914e-25c0-8536-1e741160f8c9.png)


- [injected_code.js](https://raw.githubusercontent.com/geeksonsecurity/js-malicious-dataset/master/legitimate-injected/1/injected_code.js)
    - Hash = `e51845a7756eb729efd9d5b54c681deb5178f69bd051c6dcaa2e9562ff68fe47`

ダウンロードは以下のコマンドで実行できます。

```shell:
sudo curl -s https://raw.githubusercontent.com/geeksonsecurity/js-malicious-dataset/master/legitimate-injected/1/injected_code.js \
-o /var/www/html/js/injected_code.js
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/c1878ff3-6b48-6823-a35f-a77acffccd79.png)

# 通知設定
Page Shield New Code Change Detection Alert のメール通知を設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/7ce77edb-cef3-e1c4-a245-a302b9912ce4.png)

# `.js` をキャッシュしない設定
Javascript の変更を検知させるため、キャッシュしない設定にしておきます。

- When incoming requests match…
    - `(http.request.uri.path.extension eq "js")`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/45124600-de8d-2bba-0031-552942d3acc0.png)


キャッシュする設定の場合は、Javascript の変更を検知させるためには都度キャッシュパージしてください。

:::note warn
キャッシュする設定の場合は、[Auto Minify](https://developers.cloudflare.com/speed/optimization/content/auto-minify/) によってハッシュ値が変わる可能性があるため、ご注意ください。
:::

## 参考：Purge Everything
https://gist.github.com/kyouheicf/9b59f2eaca06bdbe8bbbc1bd6b74d260

## 参考：Single File Purge
https://gist.github.com/kyouheicf/2d962c77869a12d413edb2f298fd20ff

# ページ準備
`custom.js` の中身を `code-change-alert-test00.js` として以下のように配置し

```shell:
sudo curl -s https://www.sweatybetty.com/on/demandware.static/-/Library-Sites-sweatybettylibrary/en_US/v1574703272172/js/custom.js -o /var/www/html/js/code-change-alert-test00.js
```
以下の HTML を用意します。

```html:pageshieldforcecsp00.html
<!doctype html>
<title>Code Change Alert Test</title>

<body>
    <h1>Code Change Alert Test</h1>
    <script src="js/code-change-alert-test00.js"></script>
</body>

</html>
```

# ブラウザアクセス
準備したページにブラウザでアクセスし、CSP レポートを Page Shield に送信します。
Page Shield Script Monitor にレポートするためには、`content-security-policy-report-only` レスポンスヘッダが Cloudflare によって付与される必要があります。
サンプリングが適用されるため、付与される割合は 10〜20回に1回程度のようです。
そのため、Page Shield に CSP レポートを1回だけ送信できる以下の `puppeteer` によるスクリプトを使います。

## Chrome
`your-domain.example.com` の部分を適宜変更して使います。
`--short-reporting-delay` により CSP レポートがすぐに送られます。
Developer Tools がうまく表示されない場合は「Option (Alt) + R」で何回か Developer Tools をリロードしてみてください。
Developer Tools がうまく表示されない場合でも、CSP レポートは問題なく送られます。

https://gist.github.com/kyouheicf/afef0775d561ffa265989021b2391fd7

以下のように実行し `Status: Success` となれば、CSP レポートが正常に送られたことが確認できます。

https://gist.github.com/kyouheicf/4ed9233cc128984178d8f7731127524e

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/ecd3dc4e-0a36-ecff-f0c4-c760f55e4d80.png)


## Firefox
`your-domain.example.com` の部分を適宜変更して使います。

https://gist.github.com/kyouheicf/60a6998112f087b2dfa019d1628c2a75

以下のように実行し `Status: 200` となれば、CSP レポートが正常に送られたことが確認できます。
Developer Tools では手動で `Network` タブから `Other` に絞ると Initiator `csp` による POST リクエストを確認できます。

https://gist.github.com/kyouheicf/17e7a7bff0d4bf338b4d920a7e02a6e2

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/9bf22b16-c717-eddd-4b7d-f2cf1a50955d.png)

# Reported Script の確認
以下のコマンドで最新の Reported Script を確認できます。

https://gist.github.com/kyouheicf/f0d90645f4e4b714f18ed644cdc3b9e1

## 1回目

ブラウザアクセスのスクリプトを1回実行させた結果です。
`versions` に値がないため、再度実行します。

- `"status": "infrequent"` (Added)
- `"first_seen_at": "2023-08-02T02:32:17Z"` (Added)
- `"last_seen_at": "2023-08-02T02:32:17Z"` (Added)
- `"versions": null` (Added)


```json:result1.json
{
  "id": "311a9beaf4a04bb8b584fb449c3684c1",
  "url": "https://code-change-alert.example.com/js/code-change-alert-test00.js",
  "added_at": "0001-01-01T00:00:00Z",
  "first_seen_at": "2023-08-02T02:32:17Z",
  "last_seen_at": "2023-08-02T02:32:17Z",
  "host": "code-change-alert.example.com",
  "domain_reported_malicious": null,
  "malicious_domain_categories": [],
  "url_reported_malicious": null,
  "malicious_url_categories": [],
  "first_page_url": "https://code-change-alert.example.com/pageshieldforcecsp00.html",
  "status": "infrequent",
  "url_contains_cdn_cgi_path": false,
  "versions": null
}
```

## 2回目
ブラウザアクセスのスクリプトを2回実行させた結果です。
`versions` に情報が入り、`last_seen_at` から1分以内に `fetched_at` されたことがわかります。
`hash` の値も `custom.js` の中身であることを示します。

- `"status": "infrequent"` (No update)
- `"first_seen_at": "2023-08-02T02:32:17Z"` (No update)
- `"last_seen_at": "2023-08-02T02:34:50Z"`（Updated)
- `"fetched_at": "2023-08-02T02:35:34Z"` (Added)
- `"hash": "a991b04c6a5b3f800629782e47491ea6581b11df683c17e1df54510d15114027"` (Added)

```json:result2.json
{
  "id": "311a9beaf4a04bb8b584fb449c3684c1",
  "url": "https://code-change-alert.example.com/js/code-change-alert-test00.js",
  "added_at": "0001-01-01T00:00:00Z",
  "first_seen_at": "2023-08-02T02:32:17Z",
  "last_seen_at": "2023-08-02T02:34:50Z",
  "host": "code-change-alert.example.com",
  "domain_reported_malicious": null,
  "malicious_domain_categories": [],
  "url_reported_malicious": null,
  "malicious_url_categories": [],
  "first_page_url": "https://code-change-alert.example.com/pageshieldforcecsp00.html",
  "status": "infrequent",
  "url_contains_cdn_cgi_path": false,
  "hash": "a991b04c6a5b3f800629782e47491ea6581b11df683c17e1df54510d15114027",
  "js_integrity_score": 1,
  "obfuscation_score": 93,
  "dataflow_score": 1,
  "fetched_at": "2023-08-02T02:35:34Z",
  "versions": [
    {
      "hash": "a991b04c6a5b3f800629782e47491ea6581b11df683c17e1df54510d15114027",
      "js_integrity_score": 1,
      "obfuscation_score": 93,
      "dataflow_score": 1,
      "fetched_at": "2023-08-02T02:35:34.984506Z",
      "is_malicious_code": true
    }
  ]
}
```

## コード変更する
ここで `code-change-alert-test00.js` の中身を `injected_code.js` に変更します。

```shell:
sudo curl -s https://raw.githubusercontent.com/geeksonsecurity/js-malicious-dataset/master/legitimate-injected/1/injected_code.js \
-o /var/www/html/js/code-change-alert-test00.js
```

## 3回目
ブラウザアクセスのスクリプトを3回実行させた結果です。
`last_seen_at` のみ更新されたことがわかります。再度実行します。

- `"status": "infrequent"` (No update)
- `"first_seen_at": "2023-08-02T02:32:17Z"` (No update)
- `"last_seen_at": "2023-08-02T02:38:47Z"`（Updated)
- `"fetched_at": "2023-08-02T02:35:34Z"` (No update)
- `"hash": "a991b04c6a5b3f800629782e47491ea6581b11df683c17e1df54510d15114027"` (No update)


```json:result3.json
{
  "id": "311a9beaf4a04bb8b584fb449c3684c1",
  "url": "https://code-change-alert.example.com/js/code-change-alert-test00.js",
  "added_at": "0001-01-01T00:00:00Z",
  "first_seen_at": "2023-08-02T02:32:17Z",
  "last_seen_at": "2023-08-02T02:38:47Z",
  "host": "code-change-alert.example.com",
  "domain_reported_malicious": null,
  "malicious_domain_categories": [],
  "url_reported_malicious": null,
  "malicious_url_categories": [],
  "first_page_url": "https://code-change-alert.example.com/pageshieldforcecsp00.html",
  "status": "infrequent",
  "url_contains_cdn_cgi_path": false,
  "hash": "a991b04c6a5b3f800629782e47491ea6581b11df683c17e1df54510d15114027",
  "js_integrity_score": 1,
  "obfuscation_score": 93,
  "dataflow_score": 1,
  "fetched_at": "2023-08-02T02:35:34Z",
  "versions": [
    {
      "hash": "a991b04c6a5b3f800629782e47491ea6581b11df683c17e1df54510d15114027",
      "js_integrity_score": 1,
      "obfuscation_score": 93,
      "dataflow_score": 1,
      "fetched_at": "2023-08-02T02:35:34.984506Z",
      "is_malicious_code": true
    }
  ]
}
```

## 4回目
ブラウザアクセスのスクリプトを4回実行させた結果です。
`"status": "active"` となり、再度 `fetched_at` されたことがわかります。
`hash` の値が変更となり、`versions` でも履歴が確認できます。

- `"status": "active"` (Updated)
- `"first_seen_at": "2023-08-02T02:32:17Z"` (No update)
- `"last_seen_at": "2023-08-02T02:42:21Z"`（Updated)
- `"fetched_at": "2023-08-02T02:43:26Z"` (Updated)
- `"hash": "e51845a7756eb729efd9d5b54c681deb5178f69bd051c6dcaa2e9562ff68fe47"` (Updated)


```json:result4.json
{
  "id": "311a9beaf4a04bb8b584fb449c3684c1",
  "url": "https://code-change-alert.example.com/js/code-change-alert-test00.js",
  "added_at": "0001-01-01T00:00:00Z",
  "first_seen_at": "2023-08-02T02:32:17Z",
  "last_seen_at": "2023-08-02T02:42:21Z",
  "host": "code-change-alert.example.com",
  "domain_reported_malicious": false,
  "malicious_domain_categories": [],
  "url_reported_malicious": false,
  "malicious_url_categories": [],
  "first_page_url": "https://code-change-alert.example.com/pageshieldforcecsp00.html",
  "status": "active",
  "url_contains_cdn_cgi_path": false,
  "hash": "e51845a7756eb729efd9d5b54c681deb5178f69bd051c6dcaa2e9562ff68fe47",
  "js_integrity_score": 5,
  "obfuscation_score": 5,
  "dataflow_score": 99,
  "fetched_at": "2023-08-02T02:43:26Z",
  "versions": [
    {
      "hash": "e51845a7756eb729efd9d5b54c681deb5178f69bd051c6dcaa2e9562ff68fe47",
      "js_integrity_score": 5,
      "obfuscation_score": 5,
      "dataflow_score": 99,
      "fetched_at": "2023-08-02T02:43:26.821194Z",
      "is_malicious_code": true
    },
    {
      "hash": "a991b04c6a5b3f800629782e47491ea6581b11df683c17e1df54510d15114027",
      "js_integrity_score": 1,
      "obfuscation_score": 93,
      "dataflow_score": 1,
      "fetched_at": "2023-08-02T02:35:34.984506Z",
      "is_malicious_code": true
    }
  ]
}
```

## Code change alert の確認
上記の内容でコード変更が検知されたことが確認できました。
Code change alert は1日1回、日本時間 8:30 AM 前後に通知が来ます。

### メール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/9db3eef3-4acc-a1de-fb86-a799513a7f84.png)

### Webhook
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/c6405803-2a38-a5b7-ef5b-36b51353ec97.png)


# まとめ
今回は一部の機能を確認しましたが、全体としては PCI DSS v4.0 や業界・政府による要請など、CSP を活用した対策が今後も必要になる場面があると思います。

- [PCI DSS v4.0リリース情報｜その特徴とv3.2.1との差分、対応方針について解説｜ブログ｜NRIセキュア](https://www.nri-secure.co.jp/blog/pci-dss-v4.0)
> 消費者ブラウザに読み込まれる決済ページスクリプトの管理が新たに求められるようになった。
>対策としてコンテンツセキュリティポリシー（CSP）を使用して決済ページスクリプトが未承認のコンテンツに置き換えられるのを防ぐ、サブリソースの整合性（SRI）によってスクリプトが改竄されていないことの検証を行う、などが挙げられる。

Cloudflare Page Shield では他にも機能を拡充しているので、ぜひ検討してみてはいかがでしょうか。

![p1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/d556edc8-bc78-fed1-e655-a9fd1c90eb9a.png)
![p2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/588f56cd-e501-c637-8d53-133bd0c83810.png)


# 参考

- [Define default width of Chrome DevTools window - Stack Overflow](https://stackoverflow.com/questions/58473161/define-default-width-of-chrome-devtools-window/58473581#58473581)
- [Puppeteerで使われないタブがあるのが気になる - Qiita](https://qiita.com/84q/items/683968fa8b155dd6dc8d)
- [Puppeteer で指定の Developer Tools 画面を開く - Qiita](https://qiita.com/khayama/items/dc79788b6b5a7cb6de1a)
- [HTTPie を Cloudflare API / GraphQL 用に設定する - Qiita](https://qiita.com/khayama/items/1738c3b98e9c4108a35d)
- [How to Run Puppeteer with Firefox Instead of Chrome - Bannerbear](https://www.bannerbear.com/blog/how-to-run-puppeteer-with-firefox-instead-of-chrome/)