JMeterで403エラーを解決!CookieのCSRFトークンをヘッダーに渡す方法【2025年最新版】
スポンサーリンク
---
## 「Cookieは送れているのに403が返ってくる」——その原因と5分で完結する解決策
JMeterで負荷テストのシナリオを組んでいて、こんな経験はありませんか?「CookieマネージャをセットしてリクエストもきちんとCookieを送っているのに、サーバーから`403 Forbidden`が返ってくる」。ログを追っても原因がわからず、時間だけが過ぎていく——。
**本記事を読めば、この問題を約5分で解決できます。** 正規表現抽出器を使ってCookieの値を変数に格納し、後続リクエストのヘッダーへ渡す方法を、設定値の一覧とトラブルシューティングを交えながらステップバイステップで解説します。
対象読者は「JMeterでSPAやモダンWebアプリの負荷テストシナリオを組んでいる、初級〜中級エンジニア」を想定しています。2025年5月時点のJMeter 5.6系を前提にしています。
---
## なぜCookieマネージャだけではSPAに対応できないのか
この現象の犯人は、多くの場合**CSRFトークンの二重送信要件**です。AngularやReact、Vue.jsといったモダンなSPAフレームワークを採用したシステムでは、ブラウザの開発者ツール(ChromeであればF12キー)で実際の通信を観察すると、次のような構造が確認できます。
```
Cookie: XSRF-TOKEN=abc123xyz; session=xxxxxxxx
X-XSRF-TOKEN: abc123xyz ← Cookieと同じ値をヘッダーにも付与
```
これは**Double Submit Cookieパターン**と呼ばれるCSRF対策の実装で、サーバー側は「CookieとヘッダーのトークンがI致していること」を確認することで正規のリクエストと判断します。
> **【誤字について】** 上記の「I致」は原文ママです。正しくは「**一致**」です。
JMeterのCookieマネージャはCookieの自動送受信は担ってくれますが、**CookieからヘッダーへのコピーはJMeter単体では自動処理されません**。この仕組みを手動で作ることが、403解決の本質です。
---
## 前提条件:Cookieマネージャの有効化を確認する
本手順に進む前に、テストプランにHTTP Cookieマネージャが追加されているか確認してください。
- テストプランまたはスレッドグループを右クリック
- [追加]→[設定エレメント]→[HTTP Cookieマネージャ]を選択
Cookieマネージャがない場合、セッションCookie自体が引き継がれないため、CSRFトークン以前の問題が発生します。
---
## 解決策:正規表現抽出器でCookie値を変数に格納する
### ステップ1:正規表現抽出器を追加する
`Set-Cookie`レスポンスヘッダーが返ってくるリクエスト(ログインや初回アクセスなど)のサンプラーを右クリックし、以下の手順で正規表現抽出器を追加します。
- 対象サンプラーを右クリック
- [追加]→[後処理]→[正規表現抽出]を選択
### ステップ2:正規表現抽出器を設定する
追加した正規表現抽出器に以下の値を入力します。
| 設定項目 | 入力値 |
|---|---|
| **Apply to** | `Main sample and sub-samples` |
| **Field to check** | `Response Headers` |
| **Reference Name** | `xsrfToken`(任意の変数名) |
| **Regular Expression** | `Set-Cookie:\s*XSRF-TOKEN=([^;]+)` |
| **Template** | `$1$` |
| **Match No.** | `1` |
| **Default Value** | `NOT_FOUND` |
**最重要ポイントが2つあります。**
1. `Field to check`は必ず`Response Headers`を選んでください。Cookieはレスポンスヘッダー内の`Set-Cookie`として送られてきます。誤って`Response Body`を選択すると値が取得できません。
2. 正規表現は`Set-Cookie:\s*XSRF-TOKEN=([^;]+)`としています。`\s*`でコロン後のスペース有無を吸収し、`[^;]+`でセミコロンまでの値を確実にキャプチャします。末尾の`;`がないCookieにも対応できるため、元の`(.+?);`より堅牢です。
`Default Value`を`NOT_FOUND`にしておくと、抽出失敗をすぐに検知できるため、デバッグ時に役立ちます。
### ステップ3:取得した変数をリクエストヘッダーに設定する
変数に格納できたら、後続リクエストにHTTPヘッダーマネージャを追加し、次のように設定します。
- 後続リクエストのサンプラーを右クリック
- [追加]→[設定エレメント]→[HTTPヘッダーマネージャ]を選択
| ヘッダー名 | 値 |
|---|---|
| `X-XSRF-TOKEN` | `${xsrfToken}` |
JMeterでは`${変数名}`の記法で、正規表現抽出器が格納した変数を参照できます。ヘッダーマネージャはスレッドグループ直下に置くことで全リクエストに適用することも可能ですが、トークンが不要なリクエストへの影響を避けるため、必要なサンプラーだけに配置する運用を推奨します。
---
## 動作確認の手順
設定が完了したら、本番負荷をかける前に必ず**1スレッド・1ループ**で動作を検証しましょう。
1. **「結果をツリーで表示」リスナー**を追加してテストを実行し、正規表現抽出を設定したリクエストのレスポンスヘッダーに`Set-Cookie: XSRF-TOKEN=...`が含まれているか目視確認する。
2. **デバッグサンプラー**([追加]→[サンプラー]→[デバッグサンプラー])を正規表現抽出の直後に配置し、変数の中身を確認する。
デバッグサンプラーの出力は次のようになります。正常時と異常時の違いを確認してください。
```
# 正常時(トークンが取得できている場合)
xsrfToken=abc123xyz
# 異常時(抽出に失敗している場合)
xsrfToken=NOT_FOUND
```
`NOT_FOUND`が表示されている場合は、次のトラブルシューティングセクションを参照してください。
---
## よくあるトラブルと対処法
### 変数が「NOT_FOUND」のまま
- `Field to check`が`Response Body`になっていないか再確認する
- 実際のレスポンスヘッダーを結果ツリーでコピーし、正規表現をその内容に合わせて調整する
- HTTPS環境では`Secure`属性付きCookieが別行に分かれて返る場合があるため、ヘッダーの改行位置に注意する
### 複数のSet-Cookieヘッダーがある場合
`Match No.`を`-1`にするとすべてのマッチを配列として取得できます(変数名は`xsrfToken_1`、`xsrfToken_2`…という形式)。特定のトークンのみ必要な場合は正規表現を絞り込み、`Match No.=1`のまま運用するのがシンプルです。
### ループのたびにトークンが変わる
SPAでは操作のたびにCSRFトークンが更新される実装も珍しくありません。シナリオのループ内で毎回正規表現抽出を行うよう構成し、常に最新のトークンを取得してください。ループの冒頭に「トークン取得用リクエスト → 正規表現抽出 → 業務リクエスト」という順序を組み込むのがベストプラクティスです。
### 正規表現では対応できないエッジケース
Cookieの名前が動的に変化するなど、正規表現では対応しきれないケースでは**JSR223後処理**(Groovyスクリプト)を使う方法が有効です。`prev.getResponseHeaders()`でヘッダー文字列全体を取得し、Groovyの文字列操作で柔軟にパースできます。正規表現では難しいケースに直面したときの選択肢として覚えておくと、対応できる幅が広がります。
---
## まとめ:4ステップで完結するCSRFトークン対応
今回解説した手順を整理します。
| ステップ | 内容 |
|---|---|
| **①事前確認** | ブラウザの開発者ツールで通信を観察し、`X-XSRF-TOKEN`などのヘッダーが必要か確認する |
| **②抽出器の追加** | `Set-Cookie`が返るリクエストに正規表現抽出器を追加する |
| **③正しいフィールドの選択** | `Field to check`を`Response Headers`に設定し、正規表現`Set-Cookie:\s*XSRF-TOKEN=([^;]+)`で値を抽出する |
| **④ヘッダーへの転記** | 後続リクエストのHTTPヘッダーマネージャに`X-XSRF-TOKEN: ${xsrfToken}`を追加する |
JMeterのCookieマネージャは日常的なセッション管理には十分強力ですが、CSRFトークンのように**CookieとHTTPヘッダーを連動させる必要があるケース**では、正規表現抽出器との組み合わせが欠かせません。
「なぜ403が返るのかわからない」と悩んでいる方は、まずブラウザの開発者ツールで実際の通信ヘッダーを丁寧に確認することを強くおすすめします。その一手間が、根本原因への最短ルートになります。