APIセキュリティ

今回は「OWASP API Security TOP 10」の「API3:2019 - Lack of Resources & Rate Limiting」について解説します。

まず、OWASPではLack of Resources & Rate Limitingについて英語では以下のような概要で説明しています。

Quite often, APIs do not impose any restrictions on the size or number of resources that can be requested by the client/user. Not only can this impact the API server performance, leading to Denial of Service (DoS), but also leaves the door open to authentication flaws such as brute force.

APIに対して制限を設けていない場合、サービスに影響を及ぼす攻撃を受けるリスクがあるということをここでは伝えています。またサービス不能につながるリスクだけでなく、ログインページに対してブルートフォース攻撃(この場合は総当たりでID・ポスワードの組み合わせを試す攻撃)が容易に行われ、認証回避できるリスクもあります。

APIだけでなく、Webページに対してスクリプトやツールなどを用いて容易に大量のリクエストを送信することができます。
脆弱性診断でよく利用されるツールで具体的にどのように行われるのか見てみましょう。

下はBurp Suiteをで/demo/user/§[Payload]§/showのAPIで$1$の箇所へ総当たりでペイロードをセットしてリクエストを送信する例になります。

Burp Suite Intruder Sample1

§[Paylod]§に様々な値を試すことができるのですが、このIDが推測可能な形式であれば、その形式に合わせて総当たりできるようにツールでリクエストを送信することができます。
ここではAPIのパスから推測できるように、$[Payload]$の部分にあるユーザーIDをセットするとそのユーザーの情報が出力できるAPIであることがわかります。今回はこのAPIにユーザーIDを連番で試すようにペイロードをセットします。

Burp Suite Intruder Sample2

適切にセキュリティが考慮されていない場合、例えば推測が容易なIDを利用していたり、表示の制限が設けられていない場合を含め、リクエストの送信に対する制限がない場合は、攻撃者が何度でも試すことができますので、レスポンスコードの値などからユーザーが存在するのか判定することができる場合もあります。下画面からレスポンスコードが200の箇所はIDが存在することがわかります。実は今回は短時間に大量のリクエストを送信したことで504でタイムアウトしているリクエストもあります。このようにDoS攻撃が容易に行えることがわかります。

Burp Suite Intruder Sample3

このようなリソースを枯渇させたり、総当たり攻撃のリスクを低減させるため、特定のIPアドレスやログインユーザーからある特定の期間に送信できるリクエスト数を制限することが重要になります。
対策方法は様々でAPI機能を提供するミドルウェア側で制限を設けたり、Webアプリケーションファイアウォール(以下WAF)側でアクセス制限を設けることができます。
リクエスト数をカウントするためのトラッキングする対象がIPなのかユーザーなのか、ミドルウェア側であればより詳細に制限を組める反面、パフォーマンス面も考慮する必要があります。WAFの場合は制限を処理する機能がアプリケーション側ではなくなるため、パフォーマンス面から考慮すると有効かもしれません。サイトの特製や条件にあわせて選定することが重要になります。

以下、PHPのフレームワークのLaravelでIPアドレスに対してトラッキングし、1分間に1000回までの制限を設けた例になります。
1000回を超えるとレスポンスコード429「Too many request」が返されリソースを保護することができます。

public function handle($request, Closure $next, $maxAttempts = 1000, $decayMinutes = 1)
{
  $key = $this->resolveRequestSignature($request);

protected function resolveRequestSignature($request)
{
  if ($route = $request->route()) {
  return sha1($route->getDomain().'|'.$request->ip());
}
  throw new RuntimeException('Unable to generate the request signature. Route unavailable.');
}

以下はAWS API Gateway上のRate Limitになります。

API Gateway Rate Limit

リソースの枯渇を狙ったDoS攻撃や特定の情報を盗むような総当たり攻撃に対して、APIのリソースを保護することは重要です。
APIへ過度なアクセスから保護するためにも今回ご紹介させていただいたような対策について是非ご検討していただければと思います。

関連リンク