T-Connect 2022年 公開されたソースの中の鍵

委託先が、ユーザーサイトのソースの一部を公開設定のまま GitHub に上げ、その中にデータサーバーへのアクセスキーがあった。約4年9か月、誰でもその鍵を取れる状態だった。鍵がソースに無ければ、公開の誤りは鍵の漏れにならなかった。

2022年10月7日のトヨタ自動車とトヨタコネクティッドの発表に沿って書いています。鍵の種類、権限、データサーバーの作り、委託先の名前は発表に無い。GitHub の仕組みは2026年11月時点の公式文書によります。

要点

  • 漏れた可能性があるのは、メールアドレスとお客様管理番号の29万6,019件。氏名、電話番号、クレジットカードの情報は対象外と発表された。
  • ソースが公開されていたのは2017年12月から2022年9月15日まで。委託先は取り扱いの規則に反して公開設定で上げていた。
  • データサーバーのアクセス履歴から、第三者のアクセスは確認できず、否定もできなかった。
  • ソースの非公開化は確認と同じ9月15日、アクセスキーの変更は9月17日。非公開にしても、取られた複製の中の鍵は生きている。
  • 根本の直しは、鍵をソースに置かないこと。公開の制限、検出、権限の絞り込みは、その上に重ねる網。

何が起きたか

2017年12月に公開設定で上げられたソースは2022年9月15日に非公開になり、中の鍵は9月17日に変更され、10月7日に公表された 2017年7月 この月以降に 登録した人が対象 2017年12月 委託先が公開設定で GitHub へ上げる 2022年9月15日 公開を確認 同日に非公開化 2022年9月17日 アクセスキーの 変更等 2022年10月7日 公表と、対象の 人への個別の連絡 ソースが公開 約4年9か月 中の鍵が有効 約4年9か月 非公開の後の2日 帯の長さは時間の比ではない
図1 発表された経緯と、ソースが公開されていた期間と鍵が有効だった期間
日付発表の内容
2017年7月以降T-Connect のユーザーサイトでメールアドレスを登録した人が対象[1]
2017年12月ウェブサイトの開発委託先が、取り扱いの規則に反し、ソースの一部を誤って公開設定のまま GitHub のアカウントへ上げた。2022年9月15日まで気付かず放置された[1]
2022年9月15日ユーザーサイトのソースの一部が GitHub で公開されていることを確認し、同日に非公開にした[1]
2022年9月17日データサーバーのアクセスキーの変更等を行った[1]
2022年10月7日トヨタ自動車とトヨタコネクティッドが公表。対象の人へメールで個別に連絡を始め、対象かを確かめる専用のフォームと窓口を設けた[1][2]
  • 件数はメールアドレスとお客様管理番号の29万6,019件。氏名、電話番号、クレジットカード等の情報には漏えいの可能性が無く、T-Connect のサービスそのものにも影響は無いと発表された[1]。
  • セキュリティの専門家の調査で、データサーバーのアクセス履歴から第三者のアクセスは確認できなかったが、完全には否定できないとされた。公表の時点で、不正な利用は確認されていない[1]。
  • レクサス車向けの G-Link、G-Link Lite と、MyTOYOTA、My TOYOTA+ のアプリで使うメールアドレスは、ユーザーサイトと扱いが別で、対象外とされた[1]。
  • 発表は、誰がどう公開に気付いたかを書いていない。

通った道筋

委託先が公開設定で上げたソースの中のアクセスキーを使えば、インターネットの誰でもデータサーバーのメールアドレスとお客様管理番号に届く状態だった 開発委託先 インターネット サービスの側 開発の手元 ソースの一部 公開設定で GitHub へ上げる GitHub のアカウント 公開設定のまま ソースとアクセスキー 誰でも読める 第三者 取った鍵で接続できる ユーザーサイト 鍵で接続する本来の道 データサーバー メールアドレス お客様管理番号 29万6,019件
図2 公開されたソースから、データサーバーまでの道筋。破線は、使われた跡が確認も否定もできなかった経路

発表の言葉では、公開されていたソースにデータサーバーへのアクセスキーが含まれ、それを使えばデータサーバーのメールアドレスとお客様管理番号にアクセスできた[1]。鍵がどの基盤の、どの権限の鍵かは書かれていない。

形としては、本番の鍵をソースに直書きする CWE-798 にあたる[8]。直書きの鍵は、ソースが渡る先すべてに鍵が渡る。委託先、開発者の手元、複製、そして今回は公開の場所である。

悪い例。架空のユーザーサイトの設定

// src/config/datastore.js  架空の例。値も本物ではない
export const datastore = {
  endpoint: "https://data.example.com",
  accessKeyId: "EXAMPLEKEYID0000",
  secretKey: "example-secret-not-real-0000",
};

直した例。鍵はソースに無く、実行環境が渡す

// 値は実行時に、秘密の管理の仕組みか実行環境の役割から得る
export const datastore = {
  endpoint: process.env.DATASTORE_ENDPOINT,
  credentials: await loadRuntimeCredentials("datastore-reader"),
};

直した形では、ソースが丸ごと公開されても、手に入るのは接続先の名前と役割の名前だけになる。鍵を得るには実行環境そのものに入る必要がある。

どこで止められたか

鍵を書く、公開の場所に置く、気付かず残る、誰でも接続できる、読める、の5段それぞれの下に、止める仕組みを置く 1 書く 鍵がソースに入る 2 置く 公開設定で上げる 3 残る 約4年9か月 4 使える 誰でも接続できる 5 読める 29万6,019件 置き場所 実行時に渡す 短命の資格情報 公開の制限 作成と公開の設定 委託先の置き場所 検出 secret scanning 鍵の棚卸し 権限と接続元 読める範囲を絞る 接続元を限る 記録と無効化 誰が読んだかを残す まず鍵を止める 1が根本。2から5は、1が破れたときの網
図3 漏れが進む5段と、それぞれで止める仕組み
段この件で発表されたこと止める仕組み
1 書くユーザーサイトのソースにデータサーバーへのアクセスキーが含まれていた[1]鍵をソースに置かず、実行時に渡す。長く使う鍵より期限の短い資格情報を使う[7]
2 置く委託先が取り扱いの規則に反し、誤って公開設定のまま上げた[1]委託元が管理する組織の中にだけ置かせる。組織の設定で、メンバーが作るリポジトリを非公開に限る[6]
3 残る2022年9月15日まで気付かず放置された[1]公開のリポジトリの secret scanning と push protection[4][5]。どの鍵がどこで使われているかの棚卸し
4 使える鍵の権限と接続元の制限は発表に無い鍵が読める範囲を用途に要る最小にし、接続元を実行環境に限る[7]
5 読めるアクセス履歴からは、第三者のアクセスを確認も否定もできなかった[1]読んだ主体と量が後から分かる記録。気付いたら、消すより先に鍵を無効にする[3]

1 書く。根本の段

ほかの段はすべて、ソースが外へ出る道を1つずつ塞ぐ策である。ソースが出る道は、委託先への受け渡し、開発者の手元、CIのログ、AIの道具の文脈と、公開の誤りの他にもある。鍵がソースに無ければ、どの道で出ても鍵は漏れない。置き場所と、AIの道具を使う作業での漏れ方は 秘密の鍵の扱い、静的な鍵と短命の資格情報の違いは A02 セキュリティ設定の不備 の型3にある。

2 置く。委託先の置き場所

発表によれば、委託先には取り扱いの規則があり、それに反して上げられた[1]。規則は文書だけでは、破られたときに何も止めない。GitHub の組織の設定では、メンバーが作るリポジトリを非公開に限れる。ただしこの設定は作るときだけに効き、既にあるリポジトリの公開の切り替えは止めない。組織の所有者はどの種類でも作れる[6]。委託先の個人や自社のアカウントに置かれたソースには、委託元の設定は届かない。ソースは委託元が管理する組織の中で開発させ、契約で置き場所を決める。

個人情報保護法25条は、個人データの取り扱いを委託するとき、委託先に必要かつ適切な監督を行うよう事業者に求める[9]。ソースと鍵の置き場所も、その監督の対象に入れる。

3 残る。検出

2026年11月時点の GitHub は、公開のリポジトリで secret scanning を無料で自動に行い、全部のブランチの履歴を走査し、提携先の形式の鍵は提供元へ直接知らせる[4]。push protection は鍵を含む push を止め、利用者の側の保護は公開のリポジトリへの push で既定で有効である[5]。既定の型は、主にサービスの提供元ごとの鍵の形式である。自前のデータサーバーの鍵のように組織に固有の鍵は、独自の正規表現の型を登録するか、提供元に結び付かない汎用の型とAIによる検出を使って広げる[4]。

検出は入った後

secret scanning が知らせるのは、鍵が公開された後である。知らせを受けた時点で、鍵はすでに取られたものとして扱う。

4 使える。権限と接続元

鍵が漏れたときの被害は、その鍵でできることの範囲で決まる。ユーザーサイトの鍵がメールアドレスとお客様管理番号を読めたことは発表にあるが、それ以上の権限や、どこからでも接続できたかは発表に無い。一般には、鍵ごとに用途に要る最小の権限を付け、接続を実行環境の側からに限ると、鍵の文字列だけでは届かなくなる[7]。

5 読める。記録と無効化

アクセス履歴から第三者のアクセスを確認も否定もできなかったため、対象の全員へ連絡することになった[1]。どの資格情報で、どこから、何件を読んだかが記録に残っていれば、漏れた範囲を絞れる。記録の置き方は A09 セキュリティログとアラートの不備 にある。

非公開化は9月15日、アクセスキーの変更は9月17日だった[1]。非公開にしても、公開中に取られた複製や fork の中の鍵は生きている。GitHub は、機密のデータが秘密の値なら、履歴の書き換えより先に無効化か差し替えをするよう書く[3]。漏れに気付いたら、鍵を止めることを最初にする。

守り方

根本の直し
  • 鍵をソース、設定ファイル、イメージに置かない。実行時に、秘密の管理の仕組みか実行環境の役割から渡す[7]。秘密の鍵の扱い
  • 長く使う静的な鍵をやめ、期限の短い資格情報にする。A02 セキュリティ設定の不備
  • 鍵ごとに用途に要る最小の権限を付け、読める表と列、接続元を絞る[7]。
緩和の策
  • secret scanning と push protection を、公開と非公開の両方のリポジトリで有効にする。自前の鍵には独自の型を登録する[4][5]。コミットの前で止めるなら、検出の道具を pre-commit に置く。
  • 委託先には、委託元の組織の中で開発させる。組織の設定で作るリポジトリを非公開に限り、契約に置き場所と鍵の扱いを書き、定期に確かめる[6][9]。
  • 鍵の棚卸しをする。どの鍵が、どの系の、どのソースと環境で使われ、誰が持つかを一覧にし、回転の時期を決める。
  • データの読み取りを、資格情報、接続元、件数の単位で記録する。A09 セキュリティログとアラートの不備
  • 漏れたら、無効化、差し替え、使われた跡の調査、履歴とログの掃除、再発の止めの順にする。非公開化や履歴の削除を無効化の代わりにしない[3]。秘密の鍵の扱いの漏れたときの順

参照

  1. お客様のメールアドレス等の漏洩可能性に関するお詫びとお知らせについて トヨタ自動車、2022年10月7日
  2. お客様のメールアドレス等の漏洩可能性に関するお詫びとお知らせについて トヨタコネクティッド、2022年10月7日
  3. Removing sensitive data from a repository GitHub Docs
  4. About secret scanning GitHub Docs
  5. About push protection GitHub Docs
  6. Restricting repository creation in your organization GitHub Docs
  7. Secrets Management Cheat Sheet OWASP Cheat Sheet Series
  8. CWE-798 Use of Hard-coded Credentials MITRE
  9. 個人情報の保護に関する法律 第25条 委託先の監督 e-Gov法令検索