ログに秘密のトークンが平文で残っていた:呼び忘れようがない唯一の出口で伏せる

English version

トレカダッシュ 開発の記録 / 2026年8月

iOS アプリ「トレカダッシュ」の裏側のログを調べていて、外部サービスの秘密の値(API のトークン)が、そのまま書かれているのを見つけました。2026 年 8 月 24 日のことです。

宿題として「期限なし、任意」に置いていた件でした。サーバーの実際のログを確認すると、実際に漏れていました。この記事は、原因と、「呼び忘れようがない出口で、伏字にする」直し方の記録です。

この記事は、2026 年 8 月 24 日の作業の記録から書いています。本物の値は、書いていません。

ログに、本物のトークンが出ていた

サーバーのログに、こういう行がありました(トークンの部分は、本物でした)。

WARN [再検証] 取得サービス経由での取得に失敗 [https://…]:
request to https://api.scrape.do/?token=<本物のトークン>&url=… failed, reason: read ETIMEDOUT

原因は、通信の部品(node-fetch)のエラーメッセージに、リクエストの URL が、そのまま入ることでした。URL の中のtoken=の部分に、秘密の値が含まれています。

前にも、同じことをして、直したつもりだった

2026 年 8 月 19 日にも、楽天の API の認証情報で、同じことが起きていました。そのとき、ログの文字列から秘密の値を伏せる関数(redactSecretsForLog)を作りました。ところが、この関数は、明示的に呼んだ場所にしか、効きません。取得サービスを呼ぶ場所は、50 か所以上あり、呼び忘れていたのです。

直し方:すべてのログが通る、唯一の出口で、伏せる

同じ直し方を繰り返さないよう、2 段構えにしました。

  1. ログの出口(fmt())で伏せる。サーバーの全部のログが、必ず通る、唯一の出口です。ここで伏せれば、呼び忘れようがありません。URL の中の、token、api_key、secret、applicationId、accessKey、affiliateId、setCookies などと、X の監視のログイン用クッキーの生の書き方の、両方を伏せます。
  2. 取得サービスを呼ぶ関数で、エラーを作り直す。呼び出し元に返す前に、伏せた文字列で、エラーを作り直します。関数が、データの変化で動く側(Cloud Functions のトリガー)でも使われるので、そちらのログにも効かせるためです。

実際のログの文字列 4 種で、伏せられることを確かめました。通常のログの行は、変化しないことも確かめました(deadline=2026-08-30 のような、無関係な = を、伏せてしまっては困ります)。

すでに出てしまったログは、どうするか

直しても、すでに出てしまったログには、本物のトークンが残っています。サーバーの管理者の権限でしか読めないので、緊急性は低いのですが、気になる場合は、サービスの管理画面でトークンを再発行して、サーバーの設定の値を差し替えます。この記録の時点では、これは、判断待ちの項目にしていました。

分かったこと

呼び忘れる場所が 50 あるなら、呼び忘れようがない場所で、1 度だけ行う。

この話に出てくるもの

ほかの記録

コメント

感想や、記事の間違いの指摘は、ここへ。書くには、GitHub のアカウントが要ります。

押すと、giscus(giscus.app)と GitHub に接続します。押さなければ、接続しません。詳しくはあつかいに書いています。