API認証 トークン、Web開発をしていると必ず耳にする言葉ですよね!
でも、なんだか難しそうで、セキュリティとか考えるとちょっと尻込みしちゃう…なんて人もいるかもしれません。
この記事では、API認証とトークンの基本から、JWTやOAuthといった具体的な仕組み、そして何より安全な使い方、つまりセキュアコーディングの考え方まで、図解や具体例をたっぷり交えて、どこよりも分かりやすく解説していきます!
読み終わるころには、「なるほど、トークン認証ってそういうことか!」「こうすれば安全に使えるんだ!」と、自信を持ってAPI連携に取り組めるようになっているはず。
この記事でわかること
- API認証でトークンがなぜ使われるのか、その理由がわかります。
- JWTやOAuthトークンなど、代表的なトークンの仕組みを理解できます。
- トークンを安全に扱うためのセキュアコーディングの基本を学べます。
- よくある実装ミスや注意点、その対策を知ることができます。
API認証におけるトークンの超基本
まず、API認証って何でしょう?
簡単に言うと、APIを使うときに「あなたは誰ですか?」「このAPIを使っていい人ですか?」を確認する手続きのことです。
昔ながらの方法として、毎回ユーザーIDとパスワードを送るやり方もありますが、毎回パスワードを送るのはちょっと心配ですよね。それに、他のサービス(例えば、Googleアカウントで別のアプリにログインするみたいな)と連携するときに、パスワードを直接渡すのは危険です。
そこで登場するのがトークンです!
トークンは、ユーザーが一度正しくログインしたらサーバーが発行する「許可証」のようなもの。ユーザーはこの許可証(トークン)を、パスワードの代わりにAPIリクエストに添えて送ります。サーバーはトークンを見て、「あ、許可証を持ってるね。OK!」と判断するわけです。
毎回パスワードを送る必要がないので、パスワード漏洩のリスクを減らせます。また、トークンには有効期限を設けたり、特定の操作しか許可しないように設定したりできるので、柔軟なアクセス制御が可能になります。これが、多くのAPI認証でトークンが採用されている大きな理由なんです。
Webサイトでよく使われる「セッション」という仕組みと似ている部分もありますが、トークンベース認証は特に、サーバー側でユーザーの状態を保持しない(ステートレスな)設計や、異なるドメイン間での認証(マイクロサービスなど)と相性が良いという特徴があります。
API認証で使われる代表的なトークン - JWTとOAuthを理解する
API認証で使われるトークンにもいくつか種類がありますが、ここでは特に有名な「JWT」と「OAuthで使われるトークン」について見ていきましょう。
それぞれの仕組みと特徴を知っておくと、場面に応じた使い分けができるようになりますよ。
JWT JSON Web Tokenの仕組みとメリットデメリット
JWT(ジョット、と読みます)は、情報をJSON形式で安全にやり取りするための仕様です。見た目は長い文字列ですが、実は3つの部分に分かれています。
ヘッダー.ペイロード.署名
具体的にはこんな感じの文字列です。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
それぞれの部分は、
- ヘッダー
どのアルゴリズムで署名したか(例:HS256)などの情報 - ペイロード
ユーザーIDや名前、権限など、伝えたい情報本体 - 署名
ヘッダーとペイロードを基に、秘密鍵を使って計算した値
となっています。(ヘッダーとペイロードはBase64Urlエンコードされているだけなので、誰でもデコードして中身を見ることができます。個人情報などの機密情報は直接含めないようにしましょう)。
JWTの大きな特徴は自己完結型である点。トークン自体に必要な情報(と、改ざんされていないことを証明する署名)が含まれているので、サーバー側でトークン情報を別途データベースなどに保存しておく必要が基本的にはありません(ステートレス)。サーバーの負荷を減らせるのが利点です。
一方で、一度発行したJWTは有効期限が切れるまで基本的に無効化するのが難しい、という側面もあります。有効期限を適切に短く設定したり、別の仕組み(ブラックリストなど)を組み合わせたりする工夫が求められます。
OAuth認証のフローとアクセストークンの役割
OAuth(オーオース)は、認証のための仕組みそのものではなく、「権限の委譲」を行うためのフレームワークです。よく「Googleアカウントでログイン」や「Twitterアカウントで連携」といった機能で見かけますよね。
これは、ユーザーが自分のパスワードを連携先のアプリに直接教えることなく、特定の操作(例:プロフィール情報の読み取り、ツイートの投稿)を行う権限だけをアプリに与える仕組みです。
OAuthのフローはいくつか種類がありますが、代表的な「認可コードグラント」の流れをざっくり見てみましょう。
1. ユーザー:連携アプリの「〇〇でログイン」ボタンをクリック ↓ 2. 連携アプリ:認可サーバー(Googleなど)へリダイレクト「権限ください!」 ↓ 3. ユーザー:認可サーバーでログイン&連携アプリへの権限付与を承認 ↓ 4. 認可サーバー:連携アプリへ「認可コード」を発行してリダイレクト ↓ 5. 連携アプリ:「認可コード」を使って認可サーバーへ再度アクセス ↓ 6. 認可サーバー:アクセストークン(と、場合によりリフレッシュトークン)を発行 ↓ 7. 連携アプリ:アクセストークンを使って保護されたリソース(API)へアクセス
この流れの中で出てくるのがアクセストークンです。連携アプリがAPIを利用するための「許可証」の役割を果たします。アクセストークンは通常、有効期限が短めに設定されています。
有効期限が切れた後も継続してAPIを利用したい場合は、同時に発行されることがあるリフレッシュトークンを使って、新しいアクセストークンを再取得します。
リフレッシュトークンはアクセストークンより有効期限が長く設定されますが、その分、漏洩しないよう厳重な管理が求められます。OAuthはセキュアコーディングの観点からも考慮すべき点が多いですが、安全な連携を実現する強力な枠組みです。
APIキー認証との違いは何か
トークン認証と似たものとして、APIキー認証があります。これは、あらかじめ発行された固定の文字列(APIキー)をリクエストに含めることで認証する、比較的シンプルな方式です。
APIキー認証の手軽さは魅力ですが、いくつか注意点があります。
- 誰が使っているかわかりにくい
APIキーは通常、アプリケーション単位で発行されるため、そのキーを使ってAPIを叩いているのが具体的にどのユーザーなのかを特定するのが難しい場合があります。 - 権限管理が粗い
APIキーに対して細かい権限(読み取りだけ、書き込みだけなど)を設定できないことが多いです。 - 漏洩時のリスクが大きい
APIキーが漏れると、不正利用される可能性があります。定期的なキーの変更などの運用が求められます。
一方、JWTやOAuthのトークン認証では、トークンにユーザー情報を含めたり、OAuthの仕組みで細かい権限(スコープ)を設定したりできるため、より柔軟で安全なアクセス制御が可能です。
どちらが良い悪いというわけではなく、APIの特性や求めるセキュリティレベルに応じて使い分けるのが一般的です。
比較的単純なAPIや、不特定多数ではなく決まったシステムからのアクセスを想定する場合はAPIキー、ユーザーごとの認証や細かい権限管理が必要な場合はトークン認証、といった具合です。
API認証トークンのセキュアコーディング術
さて、トークンの仕組みがわかったところで、次は最も肝心な「安全な実装方法」、つまりセキュアコーディングについて見ていきましょう。
便利なトークンも、使い方を間違えると大きなセキュリティホールになりかねません。ここでは、開発者が特に注意すべきポイントを解説します。
トークンはどこに保存するのが安全か クライアントサイド編
WebアプリケーションでAPI認証を行う際、サーバーから受け取ったアクセストークンをブラウザ(クライアントサイド)のどこに保存するかは、非常に悩ましい問題です。
よく使われる保存場所には、LocalStorage、SessionStorage、Cookieがあります。
- LocalStorage
ラウザを閉じてもデータが残る。JavaScriptから簡単にアクセスできるが、XSS(クロスサイトスクリプティング)攻撃を受けるとトークンが盗まれるリスクがある。 - SessionStorage
ブラウザタブを閉じるとデータが消える。LocalStorageと同様にJavaScriptからアクセス可能で、XSSのリスクもある。 - Cookie
サーバーとの通信時に自動で送信される。`HttpOnly`属性をつければJavaScriptからのアクセスを禁止でき、XSSのリスクを低減できる。`Secure`属性でHTTPS通信時のみ送信、`SameSite`属性でCSRF(クロスサイトリクエストフォージェリ)対策にもなる。
一概にどれが絶対安全とは言えませんが、セキュリティを考慮するなら、HttpOnly属性、Secure属性、SameSite属性を適切に設定したCookieに保存するのが比較的推奨される方法です。
ただし、Cookieには容量制限があったり、CSRF対策が別途必要になったりする場合もあります。
LocalStorageやSessionStorageを使う場合は、XSS対策を徹底することが必須条件となります。アプリケーションの要件や設計に合わせて、リスクと利便性を比較検討しましょう。
サーバーサイドでのトークン検証とセキュアな実装
クライアントからトークン付きのリクエストを受け取ったサーバーサイドでは、そのトークンが「正当なものか」「有効期限は切れていないか」「改ざんされていないか」などを厳密に検証する必要があります。この検証プロセスは、API認証のセキュリティの要です。
JWTの場合、以下の検証が不可欠です。
- 署名の検証
トークン発行時に使った秘密鍵(または公開鍵)を使って、トークンが改ざんされていないかを確認します。署名の検証を怠ると、攻撃者がペイロードを書き換えた不正なトークンを受け入れてしまう可能性があります。 - 有効期限(exp)の検証
トークンの有効期限が切れていないかを確認します。 - 発行者(iss)や利用者(aud)の検証
意図した発行者から発行され、意図した利用者のためのトークンであるかを確認します(設定されている場合)。
これらの検証は、多くの場合、ライブラリを利用して行います。ただし、ライブラリを使う際も油断は禁物です。
例えば、署名アルゴリズムを指定する`alg`ヘッダーを検証せずに鵜呑みにすると、`alg: none`(署名なし)を指定されたり、想定外のアルゴリズム(例:本来HS256のはずがRS256)を指定されて秘密鍵が漏洩したりする脆弱性につながる可能性があります。
ライブラリのドキュメントをよく読み、安全な設定で利用することがセキュアコーディングの基本となります。
OAuthのアクセストークンの場合は、トークン自体が意味を持つ文字列(Opaque Token)であることも多いです。
その場合は、トークンを受け取ったサーバーが、認可サーバーに問い合わせてトークンの有効性を確認する必要があります(イントロスペクション)。
HTTPSは絶対!トランスポート層セキュリティの確保
トークン認証を使う上で、大前提となるのがHTTPS通信の利用です。
HTTP通信は通信内容が暗号化されていないため、ネットワーク経路上で第三者に通信内容を盗聴(パケットキャプチャなど)される可能性があります。
もしHTTPでトークンをやり取りしてしまうと、そのトークンが丸見えになり、いとも簡単に盗まれてしまいます。盗まれたトークンは、正規のユーザーになりすましてAPIを不正利用するために使われかねません。
クライアント <---- [トークン丸見え!] ----> サーバー | | +---------- 攻撃者(盗聴) ------+ (HTTP通信の場合)
クライアント <==== [暗号化通信] ====> サーバー | | +---- 攻撃者(内容は解読困難) ----+ (HTTPS通信の場合)
トークンに限らず、ログイン情報など機密性の高い情報を扱う通信は、必ずHTTPSを使用しましょう。SSL/TLS証明書を導入し、常に暗号化された経路で通信を行うことが、セキュアコーディングの基本中の基本です。
最近では無料で利用できる証明書(Let's Encryptなど)もあり、導入のハードルは下がっています。
短命なアクセストークンとリフレッシュトークン戦略
アクセストークンは、APIへのアクセス権限を持つ「鍵」のようなものです。もし漏洩した場合のリスクを最小限に抑えるため、その有効期間は可能な限り短く設定することが推奨されます。例えば、数分から数時間程度です。
しかし、有効期限が短すぎると、ユーザーは頻繁に再ログインを求められることになり、利便性が損なわれます。
そこで登場するのがリフレッシュトークンです。リフレッシュトークンは、アクセストークンの有効期限が切れた際に、新しいアクセストークンを取得するためだけに使われる、もう一つのトークンです。
リフレッシュトークン自体の有効期間はアクセストークンよりも長く(数日~数週間など)設定されますが、APIへの直接アクセスには使えません。通常、アクセストークン取得のエンドポイントにしか利用できないように制限されます。
この仕組みにより、
- 普段のAPIアクセスには短命なアクセストークンを使うことで、漏洩時のリスクを低減する。
- アクセストークンの有効期限が切れても、リフレッシュトークンを使って裏側で新しいアクセストークンを取得することで、ユーザーに再ログインを強いることなくセッションを継続させる。
という、セキュリティと利便性の両立を図ることができます。
ただし、リフレッシュトークンは長期間有効なため、これが漏洩すると深刻な問題になります。リフレッシュトークンは、アクセストークン以上に厳重に、安全な方法で保管・管理する必要があります。
例えば、サーバーサイドでDBに保存し、不正利用が検知された場合に失効させる仕組みなどが考えられます。このあたりの設計もセキュアコーディングの腕の見せ所です。
署名検証を怠るな!JWTの脆弱性を突かれないために
JWTを利用する上で、絶対に省略してはいけないのが「署名の検証」です。何度でも言いますが、本当に大事なことです。
JWTの署名は、トークンが改ざんされていないことを保証するためのものです。もしサーバーが署名を検証しなければ、攻撃者はペイロード部分(ユーザーIDや権限など)を自由に書き換えたトークンを送りつけ、本来許可されていない操作を実行できてしまうかもしれません。
// 危険な例:署名を検証していない(Node.js / jsonwebtoken ライブラリ) const jwt = require('jsonwebtoken'); const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJpc0FkbWluIjpmYWxzZX0.考慮不足な署名"; // 攻撃者が is_admin: true に改ざんしたトークン const secret = 'あなたの秘密鍵'; try { // ★危険★:verifyではなくdecodeを使っている。これでは署名が検証されない! // const decoded = jwt.decode(token); // 正しい検証:verifyメソッドを使い、秘密鍵とアルゴリズムを指定する const decoded = jwt.verify(token, secret, { algorithms: ['HS256'] }); console.log('トークンは有効です:', decoded); // decoded.isAdmin が true になっている! (verifyを使えばエラーになる) } catch (err) { console.error('トークンが無効です:', err.message); }
上のコード例のように、`decode`関数は署名を検証せずにペイロードをデコードするだけなので、絶対に使ってはいけません。必ず`verify`関数(または同等の検証機能を持つ関数)を使用し、トークン発行時に使った秘密鍵(または公開鍵)と、想定しているアルゴリズムを指定して検証してください。
また、ライブラリによっては`alg: none`(署名アルゴリズムなし)を許可する設定になっている場合があるので、これも明示的に禁止するように設定しましょう。油断せず、ライブラリのドキュメントを確認し、安全な使い方を徹底することが求められます。
CSRF/XSS攻撃からトークンを守る基礎知識
トークン自体の管理だけでなく、Webアプリケーション全体のセキュリティ対策も、トークンを守る上では欠かせません。特に注意したいのが、CSRF(クロスサイトリクエストフォージェリ)とXSS(クロスサイトスクリプティング)です。
XSS (クロスサイトスクリプティング)
攻撃者が悪意のあるスクリプトをWebページに埋め込み、それを閲覧したユーザーのブラウザ上で実行させる攻撃です。もしトークンがLocalStorageなどに保存されていると、このスクリプトによってトークンが盗み取られる可能性があります。CSRF (クロスサイトリクエストフォージェリ)
ユーザーがログイン中のサービスに対して、意図しないリクエスト(例:パスワード変更、商品の購入)を攻撃者の用意した罠サイト経由で送信させる攻撃です。これらの攻撃は、直接トークンそのものを狙うわけではなくても、結果的にトークンが悪用される原因となり得ます。API認証トークンの安全性は、アプリケーション全体のセキュアコーディングの上に成り立っている、という意識を持つことが肝心です。
初心者が陥りがちな罠とAPI認証トークンの未来
ここまでAPI認証トークンの仕組みとセキュアコーディングについて解説してきましたが、実際に実装してみると、思わぬところでつまづいたり、間違いやすいポイントがあったりします。
ここでは、初心者が特に注意したい点と、今後の展望について触れておきましょう。
よくある実装ミスとデバッグの方法
トークン認証周りでよく遭遇するエラーや間違いには、以下のようなものがあります。
トークンの有効期限切れ
アクセストークンの有効期限が切れているのにAPIアクセスしようとしてエラーになる。「401 Unauthorized」などのエラーが返ってくることが多いです。リフレッシュトークンを使って新しいアクセストークンを取得する処理が正しく実装されているか確認しましょう。署名検証エラー
JWTの署名が正しくない場合に発生します。発行時と検証時で秘密鍵が異なっている、アルゴリズムの指定が間違っている、トークンが途中で壊れている、などが原因として考えられます。トークンの渡し方が違う
APIが期待しているトークンの渡し方(例:HTTPヘッダーの`Authorization: Bearer [トークン]`)と、クライアントからの渡し方が異なっている。APIのドキュメントをよく確認しましょう。CORS設定ミス
ブラウザからAPIを叩く場合、CORS(Cross-Origin Resource Sharing)の設定が正しくないと、ブラウザがリクエストをブロックすることがあります。サーバー側で適切な`Access-Control-Allow-Origin`などのヘッダーを設定する必要があります。トークンに含める情報が多すぎる
JWTのペイロードに大量の情報を詰め込みすぎると、トークンが長くなりすぎてHTTPヘッダーのサイズ制限を超えたり、パフォーマンスに影響が出たりすることがあります。含める情報は必要最小限にしましょう。API認証トークンのこれから どうなっていくの?
API認証やトークンの世界も、技術の進歩とともに少しずつ変化しています。今後注目されそうな新しい動きについても、少しだけ触れておきましょう。
最近よく耳にするのがパスキー(Passkeys)です。これは、パスワードを使わずに、スマートフォンなどのデバイスに保存された認証情報(公開鍵暗号方式を利用)を使ってログインする仕組みです。
パスワード漏洩のリスクがなく、フィッシング詐欺にも強いと期待されています。パスキーが普及すると、従来のパスワードを使ったログイン→トークン発行という流れが変わる可能性がありますが、API連携自体には依然としてトークン(特にOAuthの仕組み)が使われ続ける場面が多いと考えられます。
また、OAuthのような認証・認可の枠組み自体も、より安全で使いやすくなるように改善が続けられています。例えば、OAuth 2.0のベストプラクティスをまとめたOAuth 2.1や、より柔軟な権限管理を目指す新しいプロトコル(GNAPなど)の研究も進んでいます。
トークン自体のセキュリティを高める技術も登場しています。例えば、トークンが意図したクライアントから送信されていることを確認するためのトークンバインディングや、トークン利用時にクライアントが正当な所有者であることを証明するDPoP (Demonstration of Proof-of-Possession) といった仕組みです。これらの技術は、トークンが盗まれたとしても不正利用されにくくする効果が期待できます。
さらに、単にIDとパスワード(やトークン)だけで認証するのではなく、使っているデバイスの情報や、アクセスしている場所、時間帯といった利用状況(コンテキスト)を考慮して、アクセスを許可したり追加の認証を求めたりする、より賢い認証の仕組みも広がっていくでしょう。
いろいろな新しい動きがありますが、今日学んだトークンベース認証の基本的な考え方や、セキュアコーディングの原則は、これからもWeb開発を行う上で土台となる知識です。基礎をしっかり押さえておくことが、新しい技術に対応していく上でもきっと役に立ちますよ。
【まとめ】
最後に、この記事で学んだAPI認証トークンに関するセキュアコーディングのポイントをまとめます。
- 通信は必ずHTTPSで行う。
- アクセストークンの有効期限は短く設定する。
- リフレッシュトークンを導入し、安全に管理する。
- クライアントでのトークン保存場所はXSSリスクを考慮して選ぶ(HttpOnly Cookieなど)。
- サーバーサイドでは署名検証や有効期限検証を厳密に行う。
- JWTライブラリなどは安全な設定で利用する (`alg: none` を許さないなど)。
- XSS、CSRF対策など、アプリケーション全体のセキュリティも怠らない。
API認証とトークンは、現代のWeb開発に不可欠な要素です。仕組みを正しく理解し、セキュアコーディングの原則を守って実装することで、安全で便利なサービスを構築することができます。
まずはできるところから、一つずつ実践してみてくださいね!
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。