Cloudflare Snippets を使おう

Cloudflare Snippets を使うとエッジでJSの差し込みが非常に簡単に実行できます  
この記事では、Cloudflare Snippets (Beta) を使ってみたいと思います

## Cloudflare Snippets とは

**Cloudflare Snippets** は、2023 年 6 月にクローズドアルファ版としてリリースされたサービス  
その後、2024 Developer Week で無作為に抽出された約 5% のユーザーが利用可能となり、6 月のはじめからすべてのユーザーに開放された  

従来のルール機能（Firewall Rules、Transform Rules、Workers® など）をさらに拡張する新しい仕組みとして注目を集めています

Cloudflare が提供する CDN/WAF には、HTTP ベースの通信を柔軟に制御できる **ルール機能** が多数存在します  
変換ルール、キャッシュルール、オリジンルール、コンフィグルール、リダイレクトルールなどを駆使することで、ヘッダー操作やキャッシュ動作制御、オリジンへの接続先切り替えなどを簡単に設定できます  

**Cloudflare Snippets** は、これらのルールの仕組みをさらに拡張し、**JavaScript の断片（スニペット）** を既存のルールエンジンの中で直接実行できるようにした機能です  

Cloudflare Workers のプラットフォームを流用し、以下のような利点が得られます  

- 従来のルールでは実現しにくかった高度なロジックを、短い JavaScript コードで記述して柔軟に実行可能  
- ルールエンジンとシームレスに連携し、特定の条件に一致する通信（リクエストやレスポンス）だけをピンポイントで処理  
- CDN/WAF としての動作に組み込まれているため、**専用ドメインの設定や DNS レコード変更を要せず**、Workers に近い挙動を実現  

## Cloudflare Workers と何が違うのか

Cloudflare Workers は、Web Workers を活用して HTTP 通信に JavaScript 処理を割り込ませる強力なプラットフォームです  
一方で **Cloudflare Snippets** とは、以下の点が異なります

1. **デプロイ形態の違い**  
   Workers を利用する場合は、独自サブドメインの割り当てや DNS/CNAME レコードの設定変更など、アプリケーション側や DNS 側で調整が必要です  
   Snippets はルールエンジンの一部として動作するため、追加ドメイン設定を行わずとも導入できます

2. **起動条件の柔軟性**  
   Workers は基本的に常時有効化されますが、Snippets は Cloudflare のルールエンジンと連携し、**特定条件を満たした場合のみ** 実行可能です  
   不要な処理を行わず、必要な通信だけにスクリプトを適用できます

3. **リソース制限**  
   Snippets は「短いスクリプトを手軽に実行する」ために設計され、**最大実行時間 5ms、メモリ上限 2MB、パッケージ合計サイズ 32KB** と比較的制限が厳しめです  
   Workers はより大きなスクリプトやパッケージにも対応できます

4. **用途の違い**  
   大きめのアプリケーションを動かす場合は引き続き Workers が適します  
   Snippets は、アクセス制限やヘッダー書き換えなど、**軽量な JavaScript 処理を手早く挟み込みたい** 場合に効果的です

## Snippets の特徴

### 1. コードの再利用と一元管理

Cloudflare 上で用意する複数のルール（Firewall Rules、Transform Rules、Workers® など）にわたり、共通するロジックを一度定義した Snippet で使い回せます  
同じ条件や処理を各ルールに重複して書かずに済み、保守性を高められます

- スニペットを修正すると、参照しているルールすべてに自動反映  
- セキュリティポリシー変更や脆弱性対応などにも素早く対応

### 2. 複雑な条件ロジックの抽象化

従来のルール条件式だけでは扱いにくい複雑なロジックを、JavaScript コードでまとめておけます  
複数の HTTP ヘッダーや URI、IP アドレス範囲を組み合わせた検証など、**より自由度の高い判定** が可能です

### 3. 多彩なユースケースへの拡張

- **Firewalls / Transform / Workers®** など、Cloudflare 機能全般にまたがって適用できる  
- 複数ドメイン（ゾーン）で同じロジックを使う場合も、1 つの Snippet を再利用すれば済む  
- 条件付きで Snippet を起動させることができ、通常時の運用は軽量なままに保てる

### 4. テンプレート化による運用効率アップ

Snippets は小回りの利くスクリプトを組み合わせる設計で、1 回の通信に複数 Snippet を連鎖させることも可能です  
例として **ボット対策用の Snippet**、**特定国からのアクセスブロック用の Snippet**、**レスポンスヘッダー書き換え用の Snippet** をそれぞれ独立で用意し、実行条件を分割して設定できます  
運用をさらに細分化・最適化しやすくなります

## Snippets の基本的な使い方

1. **スニペットの作成**  
   Cloudflare Dashboard または API からルールを作成する際、繰り返し利用したい JavaScript コードを「スニペット」として切り出します

2. **ルールで参照する**  
   作成したスニペットを、他のルールや条件式と組み合わせる形で呼び出します  
   必要に応じて複数の Snippet を連鎖させることも可能です

3. **スニペットの更新**  
   既存のスニペットを編集すると、それを参照するすべてのルールの動作に影響します  
   複雑な条件や新しい要件が出た場合も、スニペットを拡張するだけで対応可能です

## Snippets で実際に何ができるのか

1. **高速なカスタムバイパスや制限**  
   特定ヘッダーを検出した際のみ処理を中断、もしくは別ルートへ転送するなど、軽量ロジックを柔軟に挟めます

2. **サードパーティ API 連携のトリガー**  
   シンプルな HTTP リクエストを Snippet 内で実行し、レスポンスやステータスで振る舞いを分岐する（リソース制限に留意が必要）

3. **レスポンス変換やカスタムヘッダー操作**  
   クライアントリクエストだけでなく、オリジンサーバーからのレスポンスを受け取り、ヘッダーの追加・書き換えなどの加工も可能

4. **一時的な緊急対応**  
   新しい脆弱性が見つかった際の緊急対策や、一時的な国別アクセス制限などを集中管理で迅速に実施できます

## Snippets のメリットと注意点

**メリット**

- **重複の削減**: 同じロジックを何度も記述しなくて済むため、ミスが減る  
- **一元管理**: スニペットを編集すれば関連ルールに一括適用でき、大規模環境でも統一ポリシーを保ちやすい  
- **高い柔軟性**: JavaScript の自由度を生かして多彩な処理を実装可能  
- **スケーラビリティ**: 複数の Snippet を組み合わせれば、要件に応じて容易に拡張できる  

**注意点**

- **リソース制限が厳しい**: 最大 5ms / 2MB メモリ / 32KB パッケージサイズのため、大掛かりな処理には向かない  
- **可読性の確保**: スニペットが増えすぎると、どのルールがどのスニペットを使っているか分かりにくくなる可能性がある  
- **テスト・検証**: スニペットを修正すると、それを参照するすべてのルールに影響が及ぶため、更新時には十分な検証が必要  
- **Workers との棲み分け**: 大規模アプリケーションには依然として Workers が適しており、Snippets は軽量なカスタマイズ向け  

## Snippets を使ってみる

Rules -> Snippets から新しい Snippet を作成します  
今回は弊社公式サイトに存在しない URL にアクセスした場合に、BASIC 認証をかけて 200 でページを表示する例を紹介します

```javascript
export default {
  async fetch(request) {
    const url = new URL(request.url);

    // BASIC 認証情報
    const validCredentials = "Basic " + btoa("kakizoe:takashi");

    // Authorization ヘッダーを取得
    const authHeader = request.headers.get("Authorization");

    // 認証情報が不正の場合は 401 を返す
    if (authHeader !== validCredentials) {
      return new Response("Unauthorized", {
        status: 401,
        headers: {
          "WWW-Authenticate": 'Basic realm="Restricted Area"',
        },
      });
    }

    // 認証成功時は通常のレスポンスを取得
    const response = await fetch(request);
    const contentType = response.headers.get("Content-Type") || "";

    // 500 エラーの場合は 200 に変更
    const statusCode = response.status === 500 ? 200 : response.status;

    // HTML の場合のみ <main class="l-main "> の中身を変更
    if (contentType.includes("text/html")) {
      const text = await response.text();

      let updatedText = text.replace(
        /<main class="l-main ">([\s\S]*?)<\/main>/,
        (match, mainInner) => {
          let modifiedInner = mainInner.replace(
            /<div class="c-breadcrumb"[^>]*>[\s\S]*?<\/div>/,
            ""
          );

          modifiedInner = modifiedInner.replace(
            /<div class="errorpage__contents"[^>]*>[\s\S]*?<\/div>/,
            ""
          );

          modifiedInner = modifiedInner.replace(
            /<div class="l-article__wrap"[^>]*>[\s\S]*?<\/div>/,
            '<div class="l-article__wrap">Kakizoe Test</div>'
          );

          return `<main class="l-main ">${modifiedInner}</main>`;
        }
      );

      return new Response(updatedText, {
        status: statusCode,
        headers: response.headers,
      });
    }

    // HTML 以外はそのまま返す
    return new Response(response.body, {
      status: statusCode,
      headers: response.headers,
    });
  },
};
```

### ルール設定例

- **カスタム フィルタ式**
- 「受信リクエストが一致する場合...」
- **フィールド**: URIパス
- **オペレーター**: 次と等しい
- **値**: /cl-kakizoe-test

これで `https://c-limber.co.jp/cl-kakizoe-test` にアクセスすると、上記の Snippet が動くように設定できます

## Snippets を動かして確認

`https://c-limber.co.jp/cl-kakizoe-test`

```
# BASIC認証
ユーザー名: kakizoe
パスワード: takashi
```

実際にアクセスすると、「本来は存在しないページにもかかわらず、200 OK を返しながら BASIC 認証が要求される！」という状態を手軽に実装できていることがわかります

## ユースケースの広がり

上記のような BASIC 認証やカスタムエラー処理以外にも、**Cloudflare Snippets** には多彩な活用方法があります

- **Bot 対策**: JavaScript でより細かくユーザーエージェントやクライアントの動きを判別
- **Geoblocking**: IP から推定される国情報などと組み合わせ、特定地域へのページアクセスを制限
- **レスポンス書き換え**: レスポンスヘッダーを追加し、キャッシュ制御ポリシーやセキュリティヘッダーを柔軟に設定
- **軽量な API ゲートウェイ**: サードパーティ API を呼び出して認証トークンを検証し、取得した結果を応じて処理を分岐

本格的なアプリケーションロジックは **Cloudflare Workers** で構築しつつ、軽量かつ頻繁に活用するカスタマイズは **Snippets** で実装する、という住み分けも可能です

## まとめ

- **Cloudflare Snippets** は既存のルール機能を JavaScript で柔軟にカスタマイズできる新サービス
- **最小限のリソース制限**と**簡単なデプロイ**で、軽量なロジックを挿し込む用途に最適
- ルールエンジンと連携するため、**特定条件でのみスクリプトを起動**させることができ、不要な処理を行わない
- 本格的なロジックは **Workers** を使い、Snippets では細かいエッジカスタマイズやユースケースをカバーする運用が向いている

今後、プレースホルダ機能などさらなる拡張も期待されており、**Cloudflare** 上でのアクセス制御やセキュリティ強化、レスポンス制御をより手軽かつ柔軟に行えるようになります  
運用負荷を抑えつつも高度な制御を行いたい場合は、ぜひ Snippets の導入を検討してみてください