3.堅牢なWebAPI設計

堅牢なAPIを設計するためのポイント

3.1. 堅牢なWeb API設計

3.1.1. Web APIの安定化

APIでのセキュリティの問題に注目し、APIについて最低限やっておくべき対策は以下の通りである。

  • サーバとクライアント間での情報不正入手
  • サーバの脆弱性による情報の不正入手や改竄
  • ブラウザからのアクセスを想定しているAPIにおける問題

3.1.2. サーバ・クライアント間での情報不正入手

HTTPSによるHTTP通信の暗号化

最も簡単でなおかつ効果のある方法はHTTPによる通信を暗号化することである。 HTTP通信を暗号化する方法として最も多く使われ、簡単に導入できるのがHTTPSというTLSによる暗号化である。

HTTPSを利用すると、サーバとクライアントの間の通信は暗号化され、途中で経由する中継サーバやネットワーク上でその中身を見ることができなくなる。

HTTPS による通信を行う場合には、サーバが送ってきた SSL サーバ証明書を受け取るが、その際にその証明書が不正なものでないかをきちんと確かめる必要がある。 それを確かめていない場合、中間者攻撃(MITM)による盗聴などが行われる危険性がある。

MITM:クライアントとサーバの通信経路の間に入り込んで中継を行うことで情報を盗み出す手法

3.1.3. ブラウザでアクセスする際の問題

XSS

Web アプリケーションにおいてHTMLにデータが埋め込まれる場合だけでなく、APIとしてJSONのようなデータを返す場合でも注意する必要がある。

例えばユーザ名に埋め込まれたJavaScript が入力のチェックをすり抜けて JSON にも格納されてしまい、それを受け取ったブラウザが画面上に表示してしまうみたいなケースがありうる。こういったことを悪用した攻撃がXSSである。

XSS対策のために一般的にはユーザからの入力をチェックしデータをユーザに返す際におかしな値を取り除く必要がある。

APIの場合は以下の通りである。

  • Content-Type に application/json を必ず返す
  • Content Sniffering を無効にするため X-Content-Type-Options: nosniff を指定する

X-Content-Type-Options はIE7以前のブラウザには効果がない。 そこで、さらなる対策として「追加のリクエストヘッダのチェック」と「JSON 文字列のエスケープ」を施す必要がある。

XSRF(CSRF)

サイトをまたいで偽造したリクエストを送りつけることにより、ユーザが意図していない処理をサーバに実行させる攻撃がXSRFである。

一般的に取られる XSRF 対策は、XSRFトークンを使う方法である。

送信元となる正規のフォームに、そのサイトが発行したワンタイムトークン、あるいは少なくともセッションごとにユニークなトークンを埋め込んでおき、そのトークンがないアクセスは拒否するというもの。

JSONハイジャック

JSONハイジャックはAPIからJSONで送られてくる情報を悪意ある第三者が盗み取ることである。 JSONハイジャックを防止するためには、現在のところ以下のような対策が有効である。

  • JSONをScript要素では読み込めないようにする
  • JSONをブラウザが必ずJSONと認識するようにする
  • JSONをJavaScriptとして解釈不可能、あるいは実行時にデータを読み込めないようにする

3.1.4. 悪意のあるアクセスへの対策

パラメータの改ざん

サーバに送信するパラメータを勝手に変更してサーバに送信することで、本来取得できない情報を取得したり、サーバ側のデータを本来ならありえない側に変更したりすること。

こうしたことを避けるために重要なのは本来アクセスができないはずの情報はサーバ側できちんとチェックし、アクセスを禁止するようにしておくことである。

3.1.5. セキュリティ関連のHTTPヘッダ

X-Content-Type-Options

X-Content-Type-Options: nosniff

X-XSS-Protection

ブラウザが備えているXSSの検出、防御機能を有効にするヘッダ。 IE8以上、Chrome と Safari にこの機能が実装されている。

X-XSS-Protetion: 1; mode=block

X-Frame-Options

このヘッダを設定することで指定したページがフレーム内で読み込まれるかどうかを制御することができる。 IE8以上、Chrome や Safari、FireFox などのブラウザが対応している。

X-Frame-Options: deny

Content-Security-Policy

読み込んだ HTML 内の img 要素、script 要素、link 要素などの読み込み先としてどこを許可するのかを指定するためのヘッダ。

XSS の危険性を低減することができる。

Content-Security-Policy: default-src `none`

Strict-Transport-Security

Http Strict Transport Security(HSTS) を実現するためのヘッダ。 このヘッダを利用すると、あるサイトへのブラウザからのアクセスを HTTPS のみに限定させることができる。

Strict-Transport-Security: max-age=15768000

Public-Key-Pins

HTTP-based public key pinning(HPKP) のためのヘッダ。 SSL証明書が偽造されたものでないかをチェックするために利用する。

Public-Key-Pins: max-age=2592000;
      pin-sha256="(省略)";
      pin-sha256="(省略)"

Set-Cookieヘッダとセキュリティ

ブラウザでセッションを扱う場合はクッキーをセッション管理に使う場合が多いが、その際にもセキュリティを考慮しておくことが可能。 そのために使うことができるのが Secure および HttpOnly という属性である。

Set-Cookie: session=(省略); Path=/; Secure; HttpOnly

Secure 属性をつけることでそのクッキーは HTTPS での通信の際のみサーバに送り返される。 HttpOnly 属性をつけることでそのクッキーは HTTP の通信のみで使われ、ブラウザで JavaScript などのスクリプトを使ってアクセスすることができないものであることを示せる。

3.1.6. 大量アクセスへの対策

ユーザごとのアクセスを制限する

一度の大量のアクセスがやってきてしまう問題を解決するための最も現実的な方法はユーザごとのアクセス数を制限することである。

単位時間あたりの最大アクセス回数(レートリミット)を決め、それ以上のアクセスがあった場合にエラーを返すようにする。

レートリミットを行うにあたっては以下のようなことを決める必要がある。

  • 何を使ってユーザを識別するか
  • リミット値をいくつにするか
  • どういう単位でリミット値を設定するか
  • リミットのリセットをどういうタイミングで行うか

制限値を超えてしまった場合の対応

レートリミットを超えた場合は 429 Too Many Requests を返す。 RFC の中でこのステータスコードについては以下のように書かれている。

  • エラーの詳細をレスポンスに含めるべきである(SHOULD)
  • Retry-After ヘッダを使って次のリクエストをするまでにどれくらい待てば良いかを指定しても良い(MAY)

レートリミットをユーザに伝える

レートリミットを行なった場合、現在のリミットアクセス数やどれくらいすでにアクセスしているのか、それがリセットされるのはいつか、などの情報をユーザに知らせてあげた方が親切である。

TwitterやGitHubでは、レートリミットを知るための専用のAPIを用意している。

HTTP のレスポンスでレートリミットを渡す場合は、HTTP ヘッダに入れるのが現時点でのデファクトスタンダード。

  • X-RateLimit-Limit・・・単位時間あたりのアクセス上限
  • X-RtaeLimit-Remaining・・・アクセスできる残り回数
  • X-RateLimit-Reset・・・アクセス数がリセットされるタイミング

3.2. Web APIの関連資料

3.2.1. Web API チェックリスト

REST API設計におけるチェックリスト。

英) https://www.kennethlange.com/rest-api-checklist/

3.2.2. Web APIの資料

資料名URL提供機関
REST API Referencehttps://nec-baas.github.io/baas-manual/latest/developer/ja/rest-ref/index.htmlNEC
REST API Checklisthttps://www.kennethlange.com/rest-api-checklist/
mdn web docs HTTPhttps://developer.mozilla.org/ja/docs/Web/HTTPMDN
RFC 6749 OAuth2.0https://tex2e.github.io/rfc-translater/html/rfc6749.htmlIETF
Google JSON style Guidehttps://google.github.io/styleguide/jsoncstyleguide.xmlGoogle
API設計まとめhttps://qiita.com/KNR109/items/d3b6aa8803c62238d990
最終更新 2025.01.19: Added ss command (683d062)