1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code の Hooks で、.env などの機密ファイルを保護する

1
Posted at

一. Hooks とは何か?何に使えるか?どんな仕組みか?

1. Hooks とは

Hooks(フック)は Claude Code が提供するインターセプト機構です。Claude がツールを呼び出す前または後に、カスタムコマンドを割り込ませて実行することができます。

Hooks がない場合、ツール呼び出しフローは次のとおりです:
ユーザーがリクエストを送る
  → Claude モデルがツールの使用を決定
    → Claude Code がツールを実行
      → 結果が Claude に返る
Hooks を導入した場合:
ユーザーがリクエストを送る
  → Claude モデルがツールの使用を決定
    → [PreToolUse Hook が発火] ← ここでインターセプトできる!
      → Claude Code がツールを実行
        → [PostToolUse Hook が発火] ← またはここで後処理を行う
          → 結果が Claude に返る

截屏2026-03-08 16.14.00.png

2. Hookの種類

種類 発火タイミング 操作をブロックできるか 主な用途
PreToolUse ツール実行 ✅ できる アクセス制御、インターセプト
PostToolUse ツール実行 ❌ できない(実行済み) フォーマット、テスト、ログ

3. よくある用途

  • アクセス制御:Claude が特定のファイル(.env など)を読み取ったり変更したりするのをブロックする
  • コードフォーマット:ファイルが変更された後、自動で Prettier を実行する
  • 自動テスト:ファイル変更時に自動でテストを走らせる
  • コード品質:ESLint / TypeScript の型チェックを実行し、Claude にフィードバックする
  • ログ記録:Claude がどのファイルにアクセスしたかを追跡する

二. Hooks の導入方法

1. 設定ファイルの場所

Hooks は Claude の設定ファイルで定義します。設定できる場所は 3 つあります:

設定ファイルのパス 適用範囲 使い所
~/.claude/settings.json グローバル、全プロジェクトに影響 共通のセキュリティルール
.claude/settings.json 現在のプロジェクト、Git にコミットされる チーム共有の設定
.claude/settings.local.json 現在のプロジェクト、Git にコミットしない 個人のローカル設定

おすすめ.env のような機密ファイルを保護する場合は .claude/settings.local.json に記述するだけで十分です。有効に機能しつつ、リポジトリにコミットされる心配もありません。

2. 設定方法

方法①:設定ファイルを直接編集する(本記事ではこちらをメインで解説)

方法②:Claude Code 内でコマンドを使う

/hooks

Claude Code のインターフェース上で /hooks と入力すると、対話形式で Hooks を追加できます。JSON の設定に不慣れな方にも使いやすい方法です。


三. Hooks の定義方法(設定の構造)

1. 設定ファイルにおける Hooks の基本構造は以下のとおりです:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "ツール名",
        "hooks": [
          {
            "type": "command",
            "command": "node ./hooks/your_hook.js"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "node ./hooks/format_hook.js"
          }
        ]
      }
    ]
  }
}

各フィールドの説明

  • matcher:監視するツールを指定します。複数のツールを | で区切ることができます(OR 条件)。例:"Read|Grep" は両方を監視します。
  • type:現在は "command" 固定です。
  • command:実行するコマンドです。Hook スクリプトは**標準入力(stdin)**からツール呼び出しの JSON データを受け取ります。

2. Claude Code の組み込みツール一覧

以下のツールを監視対象として指定できます(カスタム MCP Server を追加するとさらに増えます):

  • Read — ファイルの内容を読み取る
  • Write — ファイルに書き込む
  • Edit / MultiEdit — ファイルを編集する
  • Grep — ファイル内を検索する
  • Bash — シェルコマンドを実行する
  • List — ディレクトリ構造を一覧表示する

ヒント:Claude に「現在使えるツールをすべて教えて」と聞くと、最新の完全な一覧を教えてくれます。

3. Hook スクリプトが受け取るデータの形式

Hook が発火すると、Claude Code は stdin 経由で以下の JSON をスクリプトに渡します:

{
  "session_id": "2d6a1e4d-6...",
  "transcript_path": "/Users/ユーザー名/...",
  "hook_event_name": "PreToolUse",
  "tool_name": "Read",
  "tool_input": {
    "file_path": "/code/myproject/.env"
  }
}

4. Exit Code による動作の制御

Hook スクリプトは**終了コード(exit code)**を使って Claude Code に次の動作を伝えます:

Exit Code 意味
0 正常。ツールの実行を続行する
2 ツールの実行をブロックする(PreToolUse のみ有効)

exit code が 2 の場合、stderr に書き込んだ内容がエラーメッセージとして Claude に送られ、Claude は「Hook によって操作がブロックされた」と理解して適切に対応します。


四. 実装:Hooks を使って Claude が .env を読み取れないようにする

1.ステップ①:Hook スクリプトを作成する

プロジェクトのルートディレクトリに ./hooks/read_hook.js を作成します:

// hooks/read_hook.js
// このスクリプトは Claude が Read または Grep を実行しようとしたときに発火する

async function main() {
  // stdin から Claude が渡してきたツール呼び出しデータを読み取る
  const chunks = [];
  for await (const chunk of process.stdin) {
    chunks.push(chunk);
  }

  // Buffer を結合して JSON としてパースする
  const toolArgs = JSON.parse(Buffer.concat(chunks).toString());

  // Claude がアクセスしようとしているファイルパスを取得する
  // Read ツールは file_path、Grep ツールは path を使うため両方チェックする
  const readPath =
    toolArgs.tool_input?.file_path ||
    toolArgs.tool_input?.path ||
    "";

  // パスに .env が含まれているか確認する
  if (readPath.includes(".env")) {
    // stderr に書き込んだ内容がエラーメッセージとして Claude に送られる
    console.error("⛔ アクセス拒否:.env ファイルの読み取りは許可されていません。このファイルには機密の環境変数が含まれています。");
    // exit code 2 = このツール呼び出しをブロックする
    process.exit(2);
  }

  // 機密パスに一致しなかった場合、exit code 0 = 正常に通過させる
  process.exit(0);
}

main();

コードのロジック解説:

  1. process.stdin で Claude Code から渡された JSON データを読み取る
  2. パース後、tool_input からファイルパスを取り出す
  3. パスに .env が含まれているか確認する
  4. 含まれている → console.error でエラーメッセージを書き、process.exit(2) で操作をブロック
  5. 含まれていない → process.exit(0) で正常通過

2. ステップ②:settings.local.json を設定する

.claude/settings.local.json を開く(なければ新規作成)し、以下の設定を追加します:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read|Grep",
        "hooks": [
          {
            "type": "command",
            "command": "node ./hooks/read_hook.js"
          }
        ]
      }
    ]
  }
}

なぜ ReadGrep の両方を監視するのか?

.env の内容は 2 種類のツールから読み取られる可能性があるためです:

  • Read:ファイルの全文を直接読み取る
  • Grep:ファイル内でキーワードを検索する際にも内容が露出する

| で両方を繋ぐことで、すべての入り口をふさぐことができます。

3.ステップ③:Claude Code を再起動する

設定変更を反映するには、Claude Code の再起動が必要です:

# 現在の Claude Code セッションを終了し、再起動する
claude

4.ステップ④:動作を確認する

再起動後、Claude に .env の読み取りを試みさせてみましょう:

プロジェクトルートの .env ファイルを読み取ってください

Claude は Hook スクリプトの console.error に書いたエラーメッセージを受け取り、以下のように返答します:

.env ファイルを読み取ろうとしましたが、PreToolUse Hook によってこの操作がブロックされました。理由:⛔ アクセス拒否:.env ファイルの読み取りは許可されていません。」

5. 完全なファイル構成

your-project/
├── .claude/
│   └── settings.local.json   ← Hook の設定(Git にコミットしない)
├── hooks/
│   └── read_hook.js          ← Hook スクリプト
├── .env                      ← 保護された機密ファイル
└── ...

五. より多くの機密ファイルを保護

複数の種類のファイルを同時に保護したい場合は、read_hook.js の判定ロジックを拡張するだけです:

// アクセスを禁止するファイルパターンを定義する
const BLOCKED_PATTERNS = [
  ".env",             // 環境変数
  ".env.local",
  ".env.production",
  "id_rsa",           // SSH 秘密鍵
  ".pem",             // 証明書ファイル
  "secrets.json",     // その他のシークレットファイル
];

// いずれかの禁止パターンに一致するか確認する
const isBlocked = BLOCKED_PATTERNS.some((pattern) =>
  readPath.includes(pattern)
);

if (isBlocked) {
  console.error(`⛔ アクセス拒否:ファイル "${readPath}" は保護された機密ファイルです。`);
  process.exit(2);
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?