Unkeyを活用したAPIサーバの保護方法


現代のウェブサービスでは、APIを通じてデータや機能を提供することが一般的になっています。しかし、APIを公開するということは、不正アクセスや過剰なリクエストによるサービス障害などのリスクに常に晒されることを意味します。APIサーバを安全に運用するためには、**認証**・**認可**・**レート制限**といったセキュリティ対策が欠かせません。本記事では、APIキー管理プラットフォーム「[**Unkey**](https://www.unkey.com/)」を活用して、APIサーバをどのように保護できるかについて解説します。

![CleanShot 2025-03-04 at 14.23.42@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7565/9ed7667a-e545-49b0-9e82-007e131c5627.png)



## 1. Unkeyとは何か？
**Unkey**（アンキー）は、APIキーの発行・管理・検証を簡易かつ安全に行うためのサービス（およびオープンソースプロジェクト）です。通常、APIキーを使った認証システムを自前で実装する場合、キーの発行と保存、漏洩対策、利用状況の追跡、キーのローテーションや失効など、多くの課題に直面します。例えば、データベースにAPIキーを平文で保存すれば万一の情報漏洩時に悪用される危険があり、適切なハッシュ化や権限管理が必要です。また、開発者自身でレート制限の仕組みを実装したり、不正利用を検知してAPIキーを停止したりするのは大きな負担です。

Unkeyはこれらの課題を解決するソリューションとして設計されています。UnkeyではAPIキーそのものはデータベースに保存せず、**一方向ハッシュ**を保持します。これにより、万が一Unkey側のデータベースが漏洩しても、元のAPIキーは判明しません。開発者はUnkeyの提供するダッシュボードやAPIを通じてキーを発行・管理でき、キーごとに有効期限や使用可能回数、ひいてはアクセス可能なリソース範囲（ロール・権限）を設定することも可能です。さらに、キーの利用状況はリアルタイムで分析され、必要に応じて即座にキーを無効化（失効）することもできるため、セキュリティと運用の両面でメリットがあります。

## 2. APIサーバの保護における主要なポイント
APIサーバを保護する上で特に重要なポイントとして、**認証 (Authentication)**、**アクセス制御 (Authorization)**、**レート制限 (Rate Limiting)** の3つが挙げられます。それぞれについて概説し、Unkeyがどのように支援するかを見てみましょう。

### 認証 (Authentication)
認証とは、APIにアクセスしてくるクライアントが「誰であるか」を確認するプロセスです。APIキーは認証方式の一つであり、正しいAPIキーを提示したクライアントのみがサービスを利用できるようにします。伝統的に、APIキーの認証では**X-API-Key**のようなHTTPヘッダにキーを含めてもらい、サーバ側でその値をデータベースと照合する実装が一般的です。しかし前述のように、キーの安全な保管や比較には細心の注意が必要です。

Unkeyを使う場合、認証処理は非常に簡単になります。サーバ側でUnkeyのSDKを用いてリクエストのAPIキーを検証するだけで、キーの真正性（正しいキーかどうか）、有効期限、残り利用回数などをまとめて確認できます。Unkeyはキー発行時に各キーへユニークなIDを割り当てており、サーバはキーIDではなくキーそのもののハッシュで認証を行います。これにより、開発者自身がキーを平文で保存する必要がなく、安全な認証機構を短時間で構築できます。

![CleanShot 2025-03-04 at 14.25.29@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7565/144ba245-0fc2-4c1e-9717-0c746efa9769.png)


### アクセス制御 (Authorization)
アクセス制御（認可）は、認証済みのクライアントが「何をできるか」「どのリソースにアクセスできるか」を制御することです。APIキーを利用する場合、一般的なアプローチは**キーに紐づく権限**をあらかじめ決めておき、リクエスト時にその権限をチェックする方法です。例えば、読み取り専用のキー、書き込みが可能なキー、管理者向けのキーなど、キーの種類に応じてアクセスできるAPIエンドポイントを分けることが考えられます。

Unkeyは**ロールベースのアクセス制御 (RBAC)** にも対応しており、各APIキーに対してロールやパーミッション（権限）を付与できます。開発者はあらかじめ役割（ロール）を定義し、それに紐づく操作可能なリソースやアクションを設定します。そしてキーを発行する際に特定のロールを割り当てておけば、後は検証時にそのキーが持つロール情報を基にアプリケーション側でアクセス制御を実施できます。これにより、キーごとに細かなアクセス範囲を設定でき、万一キーが不正流用された場合でも被害を最小限に抑えることができます。

![CleanShot 2025-03-04 at 14.26.05@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7565/b45816e7-0cfb-4ff3-8db4-a278d38797f9.png)


### レートリミット (Rate Limiting)
レートリミットとは、一定時間内に受け付けるリクエストの数を制限することで、APIの乱用や過負荷を防ぐ手法です。例えば「1分間に100リクエストまで」や「1日1,000回まで」といった制限を設け、しきい値を超えるリクエストはエラー応答（HTTP 429 Too Many Requestsなど）を返します。これにより、悪意のある大量リクエストやバグによる無限ループからAPIを保護できます。

Unkeyはレートリミットの機能も提供しています。各APIキーに対して使用回数の上限や時間あたりのリクエスト数制限を設定できるだけでなく、**グローバルなレート制限**や**特定のユーザー/ IPごとのレート制限**も簡単に実装できます。Unkeyのレートリミットはエッジ側で適用されるため（ユーザーに近い場所で検査されるため）、低レイテンシーで効果的に不正なトラフィックを遮断できます。また、UnkeyのダッシュボードやAPIからレート制限の状況を監視したり、特定のキーに対する制限値を動的に変更したりすることも可能です。

![CleanShot 2025-03-04 at 14.26.37@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7565/85cbd678-1987-4da8-8f38-fa14112ca11f.png)


## 3. Unkeyを用いた実装例
次に、Unkeyを実際に用いてAPIサーバの保護機能を実装する方法を見ていきます。ここではNode.jsを用いた具体例を示しますが、Unkeyは様々な言語のSDKやREST APIを提供しているため、原理はどのバックエンド技術でも共通です。

### UnkeyによるAPIキーの発行と管理
まず、UnkeyのダッシュボードまたはAPI経由で**APIキーを発行**します。Unkeyでは**Root Key**と呼ばれる管理者権限のキーを使って、自分のサービス向けのAPIキーを発行できます。Root KeyはUnkeyのサービス利用に必要な秘密鍵で、これを使って各種操作（キー発行・失効・設定変更など）を行います。環境変数 (`UNKEY_TOKEN` 等) にRoot Keyを保存し、SDKを初期化しましょう。

```js
import { Unkey } from "@unkey/api";
const unkey = new Unkey({ token: process.env.UNKEY_TOKEN });

// 新しいAPIキーを作成（例としてownerIdにユーザIDを紐づけ）
const newKey = await unkey.keys.create({
  apiId: process.env.UNKEY_API_ID,  // Unkey上で発行対象のAPIを識別するID
  ownerId: "user_12345",            // 任意の所有者ID。自サービスのユーザID等を紐づけ可能
  prefix: "demo",                   // キーの接頭辞（任意指定、例: "demo_xxx..." の形式でキーが発行される）
  expires: Date.now() + 30*24*60*60*1000, // 有効期限 (ミリ秒指定) ここでは30日後を設定
  ratelimit: { limit: 1000, duration: 60 * 1000 }, // 1分間に1000リクエストまでに制限
  remaining: 10000                 // 総利用可能回数を10000回に設定
});
console.log("発行されたAPIキー:", newKey.key);
console.log("キーID:", newKey.id);
```

上記のコードでは、UnkeyのSDKを使って新しいAPIキーをプログラム的に発行しています。`apiId`はUnkey側で管理するAPIエンドポイントの識別子、`ownerId`はそのキーの利用者を表す任意のIDです。`prefix`を指定すると発行されるキー文字列の先頭に任意の文字列を付与できます（キー種別の識別などに便利です）。`expires`でキーの有効期限（Unixタイムスタンプ）を設定し、`ratelimit`ではキー個別のレート制限（ここでは1分間に1000回まで）を指定しています。さらに`remaining`を設定することで、そのキーが全期間を通じて使用できる総リクエスト回数を制限できます。これらのオプションにより、キーごとに細かな制御ポリシーを持たせることができます。

発行時に得られる`newKey.key`がクライアントに配布する実際のAPIキー値です（例: `demo_ABCD1234...`のような文字列）。`newKey.id`はUnkey内部でキーを管理するためのIDで、後から特定のキーを無効化（revoke）したり情報更新したりする際に使用します。

### APIリクエストの認証・認可フロー
次に、この発行したAPIキーを用いてAPIサーバへのリクエストを保護する方法を見ます。基本的な流れとしては、クライアントからのHTTPリクエストにAPIキー（例えばHTTPヘッダー`X-API-Key`）が含まれていることを確認し、そのキーをUnkey経由で検証します。検証が成功すればリクエストを処理し、失敗すれば認証エラーを返します。また必要に応じて、キーに紐づく権限情報を確認して認可を行います。

一般的なExpress.js風のミドルウェア実装例を示します。

```js
import { verifyKey } from "@unkey/api";

async function apiKeyAuthMiddleware(req, res, next) {
  const apiKey = req.headers["x-api-key"];
  if (!apiKey) {
    return res.status(401).json({ error: "APIキーが指定されていません" });
  }

  // UnkeyでAPIキーを検証
  const { error, result } = await verifyKey(apiKey);
  if (error) {
    // Unkey側との通信エラーやシステムエラーが発生
    console.error("Unkey検証エラー:", error);
    return res.status(500).json({ error: "APIキー検証中にエラーが発生しました" });
  }
  if (!result.valid) {
    // キーが無効・期限切れ・利用回数超過などの場合
    return res.status(403).json({ error: "無効なAPIキーです" });
  }

  // 必要なら result 内の情報を使ってアクセス制御を実施
  // 例えば result.key.roles に含まれるロールを確認して、管理者専用APIかを判断する等
  req.identity = result.identity;  // Unkeyが返す識別情報(所有者IDなど)をリクエストに保存
  next();
}
```

このミドルウェアでは、`verifyKey` 関数を用いてAPIキーを検証しています。UnkeyのSDKにキー文字列を渡すと、有効かどうかや期限・残り回数のチェックが行われ、その結果が `result` オブジェクトに含まれます。`result.valid` が `true`であれば認証成功、`false`であれば何らかの理由で無効となります。また、Unkeyにキー発行時 `ownerId`（あるいは`externalId`）を設定していた場合、`result.identity`にそのIDが戻ってくるため、アプリケーション側でユーザー特定に利用できます。権限に関しては、`result.key.roles` や `result.key.permissions` といったプロパティにキーに紐づいたロール・権限の情報が含まれるので、必要に応じてここで認可ロジックを追加します。

### レートリミットの適用方法
最後に、レート制限の実装です。Unkeyを使ったレートリミットは大きく2通りあります。一つは上記のようにキー発行時に各キーの`ratelimit`や`remaining`を設定し、Unkey側でキーごとの使用制限を管理する方法です。この場合、`verifyKey`を呼び出すたびに残り利用可能回数が減少し、上限に達すると`result.valid`がfalseになる（無効になる）ため、それ以上の利用を自動的にブロックできます。もう一つは、Unkeyの提供するレートリミット専用SDKを使って、**グローバルなレート制限**やキー・ユーザー以外の任意の識別子に基づく制限を行う方法です。

例えば、全ユーザーに対して一定のレート制限を設けたい場合や、APIキーではなくIPアドレスごとに制限を設けたい場合には、Unkeyの`@unkey/ratelimit`パッケージを利用すると便利です。以下にグローバルなレートリミットを適用する例を示します。

```js
import { Ratelimit } from "@unkey/ratelimit";

// グローバルに1分間に100リクエストまで許可するレートリミット設定
const globalLimiter = new Ratelimit({
  rootKey: process.env.UNKEY_TOKEN,    // Root Key（レートリミット用の権限を持つもの）
  namespace: "global",                 // 識別用の名前空間
  limit: 100,                          // 許可するリクエスト数
  duration: "60s"                      // 時間窓（ここでは60秒）
});

async function globalRateLimitMiddleware(req, res, next) {
  // すべてのリクエストに対してグローバルカウンタで制限をかける
  const identifier = "global_counter";
  const { success } = await globalLimiter.limit(identifier);
  if (!success) {
    // 制限超過
    return res.status(429).json({ error: "リクエストが集中しています。しばらく時間を置いて再試行してください。" });
  }
  next();
}
```

`Ratelimit`クラスを初期化する際に、`rootKey`にはレート制限機能を使う権限が付与されたRoot Keyを指定します（Unkeyのダッシュボードでキーを作成する際に適切な権限を与える必要があります）。`namespace`はレート制限を適用する単位の名前空間で、例えば `"global"` を使えばそのRoot Keyに紐づく全体でカウントされます。逆に、`namespace`にユーザーIDやAPIキーIDなどを動的に指定すれば、各IDごとに独立したレート制限を実現できます。上記ミドルウェアでは、全リクエストに対し共通の`"global_counter"`という識別子で`limit`関数を呼び出し、1分間に100回を超えるアクセスがあれば`success`がfalseとなりHTTP 429エラーを返しています。

Unkeyのレートリミット機能は、成功したリクエスト数や残り何回で制限に達するか等を分析する**分析機能**も備えています。これにより、どのAPIエンドポイントがどれくらい呼ばれているか、どのキーやユーザーがトラフィックの主を占めているかを可視化でき、適切なレート制限値の設定やサービス拡張の判断材料とすることができます。

## 4. 実際の使用ケース
Unkeyを導入することで得られるメリットや、有効に活用できるシナリオについていくつか紹介します。

**メリット:**
- **キー管理の簡略化と安全性向上:** 開発者が自前で安全なAPIキー管理システムを構築・運用する必要がなくなります。キーのハッシュ化保存や期限設定、失効処理が標準で提供されているため、人的ミスや実装漏れによる脆弱性を減らせます。また、キーが漏洩した場合でも即座にUnkeyのダッシュボードから該当キーを無効化でき、被害を最小限にできます。
- **柔軟な利用制限:** キー単位・ユーザー単位・サービス全体など様々なレベルでリクエスト数の制限を設けられます。これにより、無料枠のあるサービスでの**プランごとの使用量制限**や、悪意あるクライアントからの**過剰なアクセスの遮断**が容易になります。
- **分析と課金連携:** Unkeyは各キーの利用状況（何回APIが呼ばれたか、失敗したリクエスト数、レートリミット発動回数など）を分析・記録しています。これを活用すれば、APIの利用傾向を把握したり、利用料に応じた課金モデルを実現したりできます。
- **スケーラビリティとパフォーマンス:** グローバルなエッジネットワークでキー検証やレート制限が行われるため、世界中どこからのリクエストでも低遅延で処理可能です。高トラフィックなサービスでもボトルネックになりにくい設計です。

**有効なシナリオ例:**
- **パブリックAPIの提供:** 自社サービスの機能を外部開発者に公開する場合、APIキーの発行と管理は欠かせません。Unkeyを使えば、開発者ポータルを通じたキー発行、使用量のモニタリング、必要に応じたキー停止といった運用が容易になります。特に、複数の開発者にAPIを提供するSaaS企業にとって、各利用者ごとのアクセス制御やレート制限を一元的に行える点は大きな利点です。
- **モバイル/クライアントアプリとの連携API:** ネイティブアプリやシングルページアプリ（SPA）から自社APIを呼び出す際にAPIキー認証を採用しているケースでも、Unkeyは役立ちます。アプリごとにキーを発行しておけば、万一そのキーが漏洩した場合でも個別に無効化できますし、アプリ単位で利用上限を設定しておくことでサーバ側の負荷をコントロールできます。
- **テスト用・期間限定のキー発行:** 内部テストや限定公開のベータ版APIに対して、期間限定のAPIキーを発行する場合にもUnkeyは便利です。例えば「1週間だけ有効なキー」や「100回だけ使えるキー」を発行し、期間終了や上限到達後は自動的にアクセス不能にできます。これにより、トライアル提供や一時的なコラボレーション用途でキーを配布する際の管理コストが下がります。
- **マイクロサービス間の認証/認可:** サービス内部で複数のマイクロサービスがお互いにAPI通信を行う場合にも、軽量な認証手段としてAPIキーを使うことがあります。Unkeyを導入すればサービス内部のAPI呼び出しにも統一的なキー管理と認可を適用でき、監査ログの集約や障害時の原因追跡が容易になります。

## 5. まとめと今後の展望
APIセキュリティは、サービスの信頼性と利用者のデータ保護の観点から非常に重要です。認証や認可、レートリミットといった基本的な防御策を怠ると、深刻な不正アクセスやサービス停止に繋がる恐れがあります。そのため、今回紹介したUnkeyのようなツールを活用して、開発初期からセキュリティを組み込むことが望ましいでしょう。

Unkeyを導入することで、開発者は煩雑なAPIキー管理の実装から解放され、よりコアな機能開発に集中できます。また、Unkey自体もオープンソースコミュニティと共に進化を続けており、最近ではRBAC機能の追加やマルチクラウド環境での低遅延動作など、機能強化が行われています。今後もAPIセキュリティのニーズに応じて新機能や改善が重ねられていくでしょう。

最後に、セキュリティ対策に「これで完璧」という終わりはありません。Unkeyのような強力なツールを使いつつも、定期的なセキュリティレビューやキーの権限見直し、異常なアクセスパターンの監視などを継続することが大切です。APIの保護は継続的な取り組みであり、最新のソリューションとベストプラクティスを組み合わせて、安全で信頼性の高いサービスを提供していきましょう。