Apache APISIX 通过 CSRF 插件增强 API 安全性
API7.ai
February 23, 2022
CSRF(クロスサイトリクエストフォージェリ)攻撃を仕掛ける際の重要なポイントは、ターゲットサーバーが多くのリクエストの送信元が実際のユーザーなのか攻撃者なのかを区別できないようにすることです。攻撃の一般的な流れは、まず攻撃者がユーザーを攻撃者が提供するウェブページに誘導することです。このページには、ターゲットサーバーに自動的に送信されるリクエストが含まれています。ページが正常に読み込まれると、リクエストが自動的にサーバーに送信されます。サーバーにとっては、このリクエストはユーザーが通常送信するリクエストとまったく同じように見え、ユーザーの知らないうちに攻撃者によって開始されたものであることに気づきません。リクエストにはユーザーの認証情報の一部が含まれているため、攻撃者はこれらの認証情報を解析してユーザーの情報にアクセスすることができ、セキュリティリスクを生み出します。
この記事では、Apache APISIXのCSRFセキュリティプラグインであるcsrf
を紹介し、csrf
プラグインを使用してApache APISIXでAPI情報を保護する方法について詳しく説明します。
プラグインの紹介
csrf
プラグインは、Double Submit Cookie
スキームに基づいて実装されています。RFC 7231#section-4.2.1で定義されているように、GET
、HEAD
、OPTIONS
メソッドを安全なメソッドと見なします。この慣例に従い、csrf
プラグインはこれら3つのメソッドをそのまま通過させますが、他のメソッドをチェックし、安全でないリクエストを遮断します。
CSRF攻撃を防ぐためには、偽造できないトークンまたは識別子を作成し、これが攻撃者のリクエストと一緒に送信されないようにする必要があります。ユーザーは、csrf
プラグインが依存するトークンをリクエストヘッダーに含める必要があり、このトークンは署名用のキーを使用して計算されます。これにより、トークンが他の人によって偽造されることがなくなり、APIが保護されます。
ルートでcsrf
プラグインが有効になっている場合、そのルートに対するすべてのリクエストのレスポンスには、csrfトークン
を含むCookieが含まれます。
ユーザーは、このルートに対する安全でないリクエストでこのCookieを携帯し、リクエストヘッダーに追加のフィールドを追加してCookieの内容を携帯する必要があります。このフィールドは、プラグイン設定のname
値であり、これによりリクエストがCSRFプラグインのチェックを通過します。
ユーザーはプラグインの設定でランダムなキーを提供し、このキーを使用してプラグインがトークン情報をsha256ハッシュで暗号化し、CSRFトークンを生成します。これにより、トークンが偽造されないことが保証されます。
プラグインの使用方法
ルートでCSRFプラグインを有効にする
Admin APIを使用してAPISIXにルートを作成し、csrfプラグインを有効にします。
curl -i http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/hello",
"plugins": {
"csrf": {
"key": "edd1c9f034335f136f87ad84b625c8f1"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:9001": 1
}
}
}'
プラグインには3つの設定パラメータがあります。
key
: 必須フィールド、ランダムな秘密鍵の値。ユーザーはランダムなキーを提供する必要があります。expires
: オプション、ランダムな秘密鍵の有効期限、デフォルト値は7200秒。CSRFトークンはCookieを使用してクライアントに送信されるため、この設定はCookieの設定に配置され、Cookieの有効期限を制御します。また、プラグインはトークンの有効期限を判断するために時間も計算します。name
: オプション、CSRFトークンの名前、デフォルト値はapisix-csrf-token
。
リクエストを送信する
まず、POST
リクエストを使用してルートにアクセスします。
curl -i http://127.0.0.1:9080/hello -X POST
Apache APISIXはリクエストを遮断し、401
エラーを返します。返されるヘッダーには、設定されたCookieが見つかります。プラグインのname
フィールドが設定されていない場合、Cookie内のデフォルト値はapisix-csrf-token=....
です。これはCSRFプラグインによって生成されたCSRFトークンです。リクエストでは、このCookieを携帯し、トークンをリクエストヘッダーに記述する必要があります。
HTTP/1.1 401 Unauthorized
Set-Cookie: apisix-csrf-token= ${apisix-csrf-token};path=/;Expires=Mon, 13-Dec-21 09:33:55 GMT
{"error_msg":"no csrf token in headers"}
クライアント側でJavaScriptを使用する例: js-cookie
を使用してCookieを読み取り、axios
を使用してリクエストを送信します。
const token = Cookie.get('apisix-csrf-token');
const instance = axios.create({
headers: {'apisix-csrf-token': token}
});
Cookie内のトークンがリクエストヘッダー内のトークンと一致しない場合、リクエストはcsrf
プラグインによって遮断されます。以下の例を参照してください。
curl -i http://127.0.0.1:9080/hello -X POST -H 'apisix-csrf-token: ${apisix-csrf-token}' -b 'apisix-csrf-token= ${apisix-csrf-token}'
HTTP/1.1 401 Unauthorized
Set-Cookie: apisix-csrf-token= ${apisix-csrf-token};path=/;Expires=Mon, 13-Dec-21 09:33:55 GMT
{"error_msg":"csrf token mismatch"}
最後に、curl
を使用して通常のアクセスを確認します。
curl -i http://127.0.0.1:9080/hello -X POST -H 'apisix-csrf-token: ${apisix-csrf-token}' -b 'apisix-csrf-token= ${apisix-csrf-token}'
HTTP/1.1 200 OK
内部的には、プラグインはCookie内のトークンがリクエストヘッダーに含まれるトークンと一致することを確認し、署名を再計算してトークンが有効であることを確認します。
プラグインを無効にする
csrf
プラグインの関連設定情報を削除し、ルートを更新するリクエストを送信してプラグインを無効にします。
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/hello",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
まとめ
この記事では、csrf
プラグインの動作原理とその使用方法について詳しく説明しました。この記事が、Apache APISIXでCSRF攻撃を遮断するためにプラグインを使用する方法をより明確に理解し、実際のシナリオでの適用を容易にするのに役立つことを願っています。
Apache APISIXは現在、追加のプラグインを開発中であり、追加サービスの統合をサポートしています。興味がある場合は、GitHub Discussionでディスカッションを開始するか、メーリングリストを通じてコミュニケーションを取ってください。