APIキー
API Key ・ えーぴーあいきー
API の呼び出し元を示す長いランダム文字列。手軽さと、漏れたら誰でも使える危うさが表裏一体。
✦ 30秒で試す — 航海ヘッダに1行足すだけ。その手軽さが、そのまま弱点になるこのキーは今どうなっている?予想してみる概要
APIキーは、API の呼び出し元を示すために発行される長いランダム文字列です。サービスの管理画面で「キーを発行」を押すと sk_live_51Hq… のような文字列が一度だけ表示され、以降のリクエストにこれを添えると、サーバは「このリクエストはあのアカウントのものだ」と判別できます。外部サービスの API を使ったことがあれば、ほぼ確実に最初に出会う資格情報です。
最大の魅力は手軽さです。OAuth のようなリダイレクトの往復も、トークンの更新処理も要らず、発行された文字列をヘッダに付けるだけで使い始められます。その手軽さは、そのまま危うさでもあります。キーは「持っている人を本人とみなす」持参人(Bearer)型の資格情報なので、この1本の文字列が漏れれば、誰でもあなたのアカウントとして API を呼べます。しかも多くのキーには有効期限がなく、誰かが止めるまで使え続けます。
APIキーは、利便性を最優先した最も素朴な資格情報です。「漏れる前提で、漏れたときにすぐ止められるように運用する」ことが、この語彙の核心になります。
なぜ生まれたか
Web の API が公開され始めた2000年代、提供者には「誰が呼んでいるかを知りたい」という切実な事情がありました。完全に匿名の API では、利用量の集計も課金もできません。暴走したクライアントを止めるレート制限も「全員まとめて」しかかけられません。かといって、機械同士の通信にユーザー名とパスワードを毎回送らせるのは筋が悪いものでした。ユーザーの代理でアクセスする委譲の仕組み(のちの OAuth)はまだ整っておらず、「開発者が自分のプログラムから呼ぶ」という単純な用途には大げさでもありました。
そこで採られたのが、「開発者ごとにランダムな文字列を1本発行し、それを名札として付けてもらう」という最小限の仕組みです。提供者はキーごとに利用量を集計し、課金し、制限をかけ、悪用があればそのキーだけを無効にできます。Google Maps API などの初期の公開 API がこの方式を広め、「まず API キーを発行してもらう」は開発者体験の定番になりました。
ところが、キーの数が増え、ソースコードが Git で公開される時代になると、新しい問題が表面化します。キーがコードと一緒に公開リポジトリへ流れ出す事故です。これに対応して、2010年代後半からは「キーの形式そのものを見つけやすく設計する」「公開されたキーを提供者に通報して自動で止める」といった、漏えいを前提にした仕組みが整っていきました。
詳細
識別なのか、認証なのか
APIキーを理解するうえで大事なのが、「識別(identification)」と「認証(authentication)」のどちらの役割を担っているか、という区別です。Google Maps の JavaScript 用キーのようにブラウザへ埋め込む前提のキーは、ページのソースを見れば誰でも読めます。秘密として守れないので、実質は「どのプロジェクトの利用かを仕分ける名札」です。このため、使える Web サイト(Referer)やアプリを制限して悪用の幅を狭めます。一方、サーバの中だけで保持する秘密のキーは、「キーを知っていること」をもって呼び出し元を確かめる認証手段として働きます。ただしその場合でも、キーが表すのは通常「アカウントやプロジェクト」で、操作している人間ではありません。
「誰の権限で、何を、いつまで許すか」を細かく制御したい場面では、より重い仕組みが選ばれます。スコープと有効期限を持つ OAuth のアクセストークンや、それを自己完結的に検証できる形にした JWT、通信路の両端で証明書を確かめ合う mTLS です。注意したいのは、JWT の署名が防ぐのは「中身の改ざん」であって、「盗まれて使われること」ではない点です。JWT も持参人型なので、盗まれれば APIキーと同じように使われます。これらの仕組みが強いのは、有効期限が短く、スコープが絞られているので、盗まれても被害が時間と範囲で区切られるからです。例外は mTLS で、秘密鍵そのものは通信に載らないので、盗み見ただけでは使えません。
発行・保存・照合の仕組み
典型的な流れを追ってみます。(1)開発者が管理画面で「キーを発行」を押すと、サーバは暗号論的に安全な乱数から 128〜256 ビット程度のキーを作り、画面に一度だけ表示します。(2)サーバのデータベースには、キー本体ではなく、その SHA-256 などのハッシュ値を保存します。管理画面で「どのキーか」を見分けられるように、先頭の数文字(sk_live_51Hq…)だけは別に残します。(3)クライアントはリクエストのたびに、Authorization: Bearer や X-API-Key といった HTTP ヘッダにキーを載せます。(4)サーバは受け取ったキーをハッシュし、その値でデータベースを引いて持ち主を特定し、そのアカウントの権限・プラン・レート制限を当てはめます。
保存のハッシュが、パスワードのときと違うことに注意してください。パスワードは人が覚えられる程度の短い文字列なので、ハッシュが漏れると総当たりで元に戻されてしまいます。そこで bcrypt や Argon2 のような「わざと遅い」ハッシュで総当たりを遅くします。APIキーは 128 ビット以上のランダムな値なので、総当たりはそもそも成り立ちません。速い SHA-256 で十分です。しかも同じキーからは必ず同じハッシュが出るので、ハッシュ値をそのままデータベースの検索キーにできます。遅いハッシュを毎リクエストで計算するのは、無駄が大きいだけです。
キーは平文のまま送られるので、HTTPS が絶対の前提です。キーを URL のクエリに載せる方式も昔は多く使われましたが、アクセスログやブラウザの履歴、Referer ヘッダに残ってしまいます。いまはヘッダで送るのが原則です。
見つけやすいキーを設計する
最近のキーは、見ただけで種類が分かる形をしています。Stripe の sk_live_(本番の秘密キー)と pk_live_(公開してよいキー)、GitHub の ghp_(個人のアクセストークン)、AWS の AKIA(長命のアクセスキー)などです。GitHub は2021年にトークンの形式を改め、接頭辞に加えて末尾にチェックサムを付けました。
接頭辞は、漏えいを機械で見つけるための工夫です。正規表現で拾いやすく、チェックサムで本物らしさを確かめられるので、誤検知が減ります。GitHub の secret scanning は、公開リポジトリに push されたキーをこの形で検出し、提供者に通報します。通報を受けた提供者は、キーを自動で失効させたり、持ち主に警告したりします。push そのものを止める push protection もあります。提供者の側から見ると、「自社のキーに固有の接頭辞を付け、スキャンの提携先に登録すること」が、利用者を守る設計の一部になっています。
定番の事故と、本当の対策
APIキーの事故で圧倒的に多いのが、ソースコードへの直書きと、Git リポジトリへのコミットです。「気づいてすぐ消した」は、対策になりません。Git の履歴には過去のコミットがすべて残り、公開リポジトリは攻撃者のボットが常時スキャンしています。クラウド(AWS など)のアクセスキーを push すると、数分以内に不正利用が始まることもあります。暗号通貨の採掘用に大量のサーバが立てられ、数百万円の請求が届いた、という事故は毎年のように報告されています。
漏れたと分かったときにすべきことは、消すことではなく、失効させてローテーションすることです。キーの有効・無効を決めているのは発行元のサーバで、リポジトリではありません。削除コミットを積んでも、履歴を書き換えて force push しても、すでに取られた写しは攻撃者の手元で有効なままです。発行元でキーを失効させて、新しいキーに入れ替えたとき、はじめて写しは使えなくなります。
下の部品で確かめてください。キーをうっかりコミットし、削除コミットを積んだり履歴を書き換えたりしても、不正利用のメーターが止まらないことを見てから、発行元でキーを失効させます。
開発者の手元に、本番の API キーがあります。まずは金の輪のチップを公開リポジトリへドラッグして、うっかりコミットしてみてください(タップでもおまかせで運べます)。
予防の側では、キーをコードに書かず、環境変数やシークレット管理の基盤から実行時に注入します。そのうえで、Gitleaks などのスキャナをコミット前のフックと CI/CD に組み込み、混入を機械で止めます。
ローテーションと運用設計
キーは「いつか漏れる」前提で運用します。核になるのがローテーション(定期的な交換と、疑わしいときの緊急の交換)です。ここで効くのが、1つのアカウントに複数のキーを併存させられる設計です。新しいキーを発行し、利用側を順に切り替え、古いキーの利用がゼロになったのを確かめてから失効させる、という手順なら止めずに交換できます。
逆に1本しか持てない設計だと、交換の瞬間に必ず止まります。その結果、「怖くて何年も替えられない」キーが生まれます。あわせて、キーごとに権限を絞り(読み取り専用のキー、特定のリソースだけのキー)、最小権限の原則に沿わせます。使える接続元の IP アドレスを制限し、利用状況を監視して、ふだんと違う呼び出しを検知します。手軽に始められるのが APIキーの美点ですが、本番運用に載せた瞬間から、それは発行から失効までを管理する「秘密情報」の一つになります。
試問
開発者の手元に本番の API キーがあり、公開リポジトリ(誰でも見られるコードの置き場)の Git 履歴、キーの形を探すスキャンボット、キーを発行した API 提供者が並んでいます。キーのチップを公開リポジトリへ運ぶとうっかり push したことになり、そのあとは道具箱の3つの対策(キーを消してコミット・履歴を書き換える・発行元でキーを失効)を、効きそうな相手へドラッグして使えます(タップでも使えます)。
開発者の手元に、本番の API キーがあります。まずは金の輪のチップを公開リポジトリへドラッグして、うっかりコミットしてみてください(タップでもおまかせで運べます)。
