マガジン

エラーログをAIに貼る前の伏せ字ルール:トークン・パス・メールの置き換え方

AIを使いこなす

Claudeで執筆し、GPTで自動校閲・修正しています。

ログを示す用紙の三箇所を白い紙片で覆い、情報を伏せたイラスト
記事の内容をもとに制作したAI生成イメージです。実際の製品画面や検証結果の写真ではありません。

結論から言うと、ログは「黒塗り」ではなく「名前付きの代役への置き換え」で伏せるのが安全で、しかも調査にも使えます。トークンやパスワードは値を丸ごと <TOKEN_1> のようなラベルに替えます。ホームディレクトリのユーザー名やメールアドレス、社内ホスト名も同様に替えます。一方で、エラーの種類、メッセージ、行番号、関数名、ライブラリのバージョン、プロジェクト内の相対パス、HTTPステータスはそのまま残します。AIが原因を推測する材料は、ほとんどこの「残す側」にあるからです。 この記事では、置き換えの原則、置き換え前後の対応例、残す・消す・迷うの判断表、貼る直前に全行を見直すチェックリスト、AIに渡す依頼文を順に示します。

この記事の目次
  1. 置き換えの原則:ラベルは一貫させ、形は残す
  2. 置き換え前後の対応例
  3. 残す・消す・迷うの判断表
  4. 手順:貼る前の置き換え作業
  5. AIに渡す依頼文の例
  6. すでに貼ってしまったときの対応
  7. 迷ったときの基準

置き換えの原則:ラベルは一貫させ、形は残す

伏せ字で失敗しやすいのは、*** や xxxx で全部を同じ見た目にしてしまうことです。次の3点を守ると、情報の欠落を最小限にできます。

  1. 同じ値には同じラベルを付ける。 同じメールアドレスが3行に出るなら、3行とも <EMAIL_1> にします。別の人なら <EMAIL_2> です。「同じユーザーで失敗している」のか「別々のユーザーで失敗している」のかが読み取れます。
  2. 種類が分かるラベルにする。 <TOKEN_1>、<DB_PASS>、<HOST_DB> のように、何の値かを名前で示します。
  3. 形が原因になりうるときは、形を文章で補う。 「トークンの形式が不正」というエラーなら、長さや先頭の特徴が手がかりになります。その場合も実際の値は書かず、<TOKEN_1>(英数字40文字、先頭に Bearer が付く) のように説明だけを添えます。

ログに出してはいけない情報の考え方は、OWASP Logging Cheat Sheet が参考になります。この資料は、パスワード、暗号鍵、セッションID、アクセストークン、データベース接続文字列などを、ログから除外するか、マスク・ハッシュ化などをすべき対象に挙げています。ファイルパスや内部ネットワーク名、氏名・メール・電話番号のような情報も、リスク評価や規制に応じて特別な扱いが要りうると述べています。AIに貼る場合も、ログを外部に持ち出す行為である点は同じなので、この線引きをそのまま使えます。

置き換え前後の対応例

次は説明用の例です。値はすべて架空で、実際のサービスのログではありません。

置き換え前:

Error: connect ECONNREFUSED 10.0.12.34:5432
    at /Users/taro.yamada/work/shop-api/src/db.js:42:11
DATABASE_URL=postgres://shop_admin:Zx9-example-pass@db-internal.example-corp.co.jp:5432/shop
POST /api/login 401 {"email":"hanako.sato@example.co.jp"}
Authorization: Bearer EXAMPLE-TOKEN-0000000000000000

置き換え後:

Error: connect ECONNREFUSED <IP_DB>:5432
    at /Users/<USER>/work/shop-api/src/db.js:42:11
DATABASE_URL=postgres://<DB_USER>:<DB_PASS>@<HOST_DB>:5432/<DB_NAME>
POST /api/login 401 {"email":"<EMAIL_1>"}
Authorization: Bearer <TOKEN_1>

変えた箇所と、残した箇所の理由を整理します。

  • 10.0.12.34、置き換え:<IP_DB>、理由:社内ネットワークの構成が分かるため。ポート 5432 は残す(「接続拒否」の調査でPostgreSQLの標準ポートだと分かる)
  • /Users/taro.yamada/、置き換え:/Users/<USER>/、理由:氏名由来のユーザー名が入りやすいため。work/shop-api/src/db.js:42:11 は残す(どのファイルの何行目かが原因特定の中心)
  • 接続文字列のユーザー・パスワード・ホスト・DB名、置き換え:<DB_USER> <DB_PASS> <HOST_DB> <DB_NAME>、理由:接続文字列は丸ごと秘密として扱う。postgres:// と全体の構造は残す
  • メールアドレス、置き換え:<EMAIL_1>、理由:後述の理由で個人情報にあたりうるため
  • Bearerトークン、置き換え:<TOKEN_1>、理由:そのまま使われると認証を突破される値のため。Bearer という方式名は残す

Error: connect ECONNREFUSED の行、401、POST /api/login といった部分は一切変えていません。このままでもAIは「DBに接続できていない」「ログインAPIが401を返している」と読み取れます。

残す・消す・迷うの判断表

  • エラー名・メッセージ本文、扱い:残す、置き換え例・メモ:メッセージに値が埋め込まれている場合だけ、その値を置き換える
  • 行番号・列番号・関数名、扱い:残す、置き換え例・メモ:原因調査の主な手がかり
  • ライブラリ・ランタイムのバージョン、扱い:残す、置き換え例・メモ:既知の不具合との照合に使える
  • プロジェクト内の相対パス、扱い:残す、置き換え例・メモ:src/db.js:42 のような形
  • HTTPメソッド・パス・ステータス、扱い:残す、置き換え例・メモ:クエリ文字列(?token=... など)は別扱い
  • APIキー・トークン・パスワード・Cookie・セッションID、扱い:必ず置き換える、置き換え例・メモ:<TOKEN_1>、<SESSION_1> など
  • 接続文字列・秘密鍵・署名付きURL、扱い:必ず置き換える、置き換え例・メモ:全体を <DB_URL> にしてもよい
  • 絶対パス中のユーザー名、扱い:置き換える、置き換え例・メモ:/Users/<USER>/、C:\Users\<USER>\
  • メールアドレス・氏名・電話番号、扱い:置き換える、置き換え例・メモ:<EMAIL_1>、<NAME_1>
  • 社内ホスト名・内部IP・社内URL、扱い:置き換える、置き換え例・メモ:<HOST_DB>、<IP_DB>
  • 顧客ID・注文番号、扱い:迷う、置き換え例・メモ:他の情報と突き合わせて個人が分かるなら置き換える
  • リクエスト/レスポンス本文、扱い:迷う、置き換え例・メモ:構造(キー名)だけ残し、値を置き換える
  • タイムスタンプ、扱い:迷う、置き換え例・メモ:順序の調査に必要なら残す。時刻が不要なら削ってよい

メールアドレスを置き換える根拠

個人情報保護委員会のQ&Aは、メールアドレスのユーザー名やドメイン名から特定の個人を識別できる場合(例として kojin_ichiro@example.com のような形)は、そのアドレス単体で個人情報に該当するとしています。それ以外でも、他の情報と容易に照合でき個人を識別できるなら、個人情報にあたる可能性があります(個人情報保護委員会「ガイドライン」に関するQ&A のQ1-4など)。ログのメールアドレスは、同じログ内のユーザーIDや氏名と並んでいることが多いので、迷うより置き換えるほうが確実です。ただしこれは日本の個人情報保護法の考え方の一例で、貼ってよいかどうかの適法性は、所属組織の規程や委託・提供の取り決めで変わります。業務のログなら、社内の情報管理ルールの確認が先です。

手順:貼る前の置き換え作業

  1. 元のログを複製する。 元のファイルは触らず、コピーに対して作業します。
  2. 貼りたい範囲を絞る。 エラーが出た箇所の前後と、スタックトレースだけで足りることが多いです。ログ全体を貼る必要はありません。
  3. エディタの検索機能で、秘密の入口を探す。 token、secret、password、passwd、key、Authorization、Cookie、://(接続文字列やURL)、@(メールや接続文字列)を検索して、該当行を置き換えます。この検索語は取りこぼしを前提とした出発点です。
  4. ユーザー名を一括置換する。 自分のホームディレクトリ名を全文検索し、<USER> に一括で置換します。一括置換なら、同じ値に同じラベルを自然に付けられます。
  5. 残りを目で全行読む。 検索で拾えない値(独自形式のID、本文中の氏名など)は、人が読むしかありません。次のチェックリストを使います。
  6. 置き換えた事実をAIに伝える。 下の依頼文のとおり、ラベルの意味を一行で説明しておきます。

貼り付け前の全行チェックリスト

貼る直前に、上から1行ずつ読んで確認してください。

  • [ ] 認証ヘッダー(Authorization、X-API-Key など)の値がラベルになっている
  • [ ] Cookie と Set-Cookie の値、セッションIDが残っていない
  • [ ] URLのクエリ文字列(?token=、?key=、?signature= など)の値が置き換わっている
  • [ ] :// を含む接続文字列で、ユーザー・パスワード・ホスト名が置き換わっている
  • [ ] 環境変数の出力(env やデバッグ表示)に秘密の値が混ざっていない
  • [ ] JWTのようなトークンは、全体をラベルにしている(JWTは中身を読み取れる形式で、暗号化されているとは限らないため)
  • [ ] 絶対パスのユーザー名・会社名・案件名が置き換わっている
  • [ ] メールアドレス、氏名、電話番号、住所がラベルになっている
  • [ ] 内部IP、社内ホスト名、社内URLが置き換わっている
  • [ ] JSON本文やSQLの値の中に、顧客情報が残っていない
  • [ ] 同じ値には同じラベル、別の値には別のラベルが付いている
  • [ ] エラー名、行番号、バージョン、HTTPステータスは消していない
  • [ ] 置き換えのためにファイル全体を貼り直していない(元のログの複製から作業した)

AIに渡す依頼文の例

置き換えが済んだログは、次のように依頼すると、AIが山かっこの中身を聞き返すのを防げます。

次のエラーログの原因と修正方法を教えてください。

【環境】Node.js(バージョン:○○)、Express、PostgreSQL
【やりたいこと】ログインAPIからDBに接続したい
【ログについて】秘密と個人情報は<>のラベルに置き換え済みです。
  同じラベルは同じ値を指します。実際の値は送れないので、
  値が必要な場合は「どんな形式の値か」を質問してください。
【お願い】
  1. 考えられる原因を可能性の高い順に3つまで
  2. それぞれを確かめる手順
  3. 修正するときは、接続情報を環境変数から読む形で書いてください

--- ログ ---
(ここに置き換え済みログを貼る)

「実際の値は送れない」と先に伝えるのがポイントです。AIが「パスワードを教えてください」と返すのを防げますし、コード例にも秘密を直書きしない形で書かせやすくなります。

すでに貼ってしまったときの対応

秘密の値をAIの入力欄、チャット、チケットなどに貼ってしまったら、まずその値を無効にして新しいものに替えることを優先します。GitHubのシークレットスキャンの説明も、秘密が漏れた場合は、履歴から消す作業より先にその認証情報をすぐローテーション(再発行して旧版を失効)するよう勧めています(GitHub Docs: Secret scanning)。これはGitHub上の漏えいを前提にした説明ですが、「見られた可能性のある値は使い続けない」という考え方は、AIへの貼り付けにも当てはまります。

なお、AIサービスの設定で「入力を学習に使わない」にしても、その入力が秘密として守られると保証されるわけではありません。保存期間や社内閲覧の範囲は別の話なので、秘密の値は設定に頼らず、最初から送らないのが基本です。会社のアカウントで使っている場合は、貼ってよい情報の範囲を所属組織のルールで確認してください。

迷ったときの基準

最後に、判断に迷う行への基準を一つだけ挙げます。「その行を消しても、AIが原因を考えられるか」を自問し、考えられるなら置き換えます。 値そのものが原因の手がかりになる場合(形式不正、桁数、文字種など)も、値は書かず、形の説明に替えます。迷う行を残すより、一度置き換えてAIに質問させるほうが、後で取り返しがつかなくなる事態を避けられます。

出典・参考資料