前回の記事ではREST APIを設計する上での認証認可について基本的な考え方をまとめました。
https://serverless.co.jp/blog/mi3tt22d0/
第二回のこの記事ではリクエスタからAPIへ通信を行う際の考慮点やパラメータの渡し方についてまとめていきます。
パラメータの推奨される受け渡し方法
前回の記事で以下の通り記載しました。
セキュリティのため、認証に用いる情報はHTTPヘッダーに含めて送信し、URLに認証情報を含めないようにします。(セキュリティの観点から、URLパラメータに認証情報を含めないようにする)
これがなぜなのかについてまずはまとめていきます。
REST APIは以下の論文で定義されたのが土台といわれています。
https://ics.uci.edu/~fielding/pubs/dissertation/top.htm
そしてこの考え方に従って設計されたREST API は RESTfulともいわれます。基本的な考え方はHTTPの標準的なお作法にのっとりましょう、というものです。HTTPは非常に汎用性の高いプロトコルであり、リクエスタがサーバにデータを渡すやり方も複数用意されています。
一般的には、URLパラメータ(https://xxx.com/?secret=yyyy)はリソースの識別子やフィルタリング、クエリに使われ、ヘッダはメタ情報(認証情報(Authorization: Bearer yyyy)、コンテンツタイプ、リクエストタイプなど)に使われるべきとされています。これに従うことで、RESTfulな設計に従ったAPIを提供することができます。
このため多くのHTTPやWEB関連のミドルウェアがこの考えたかに従って開発されています。例えばnginxはhttps://xxx.com/?secret=yyyy へのアクセスはデフォルトでログに記録されます。一方HTTPヘッダーのAuthorization: Bearer yyyy はデフォルトではログに保存されません。当然yyyyの情報はログに残さないことが望ましいのは言うまでもありません。
CDNとの連携でも同じ点に注意するひつようがあります。CDNは一般的にアクセスされたURL全体をキーとしてオブジェクトをキャッシュします。つまりhttps://xxx.com/?secret=yyyy へのアクセスの場合yyyyがCDN側のログにも保存され、コンテンツはそれに応じでキャッシュされます。(https://xxx.com/ 単位ではなく、https://xxx.com/?secret=yyyy 単位でキャッシュされます)別のユーザーがhttps://xxx.com/?secret=zzzz へアクセスした場合、そのキャッシュは使われずオリジンからコンテンツが再度読み込まれることとなるため、費用、パフォーマンス、セキュリティすべての面でデメリットが生じます。
この様な理由からセンシティブな情報はURLパラメータではなくHTTPヘッダを用いることが推奨されています。
HTTPS (SSL/TLS) の利用必須化とHTTP Strict Transport Security (HSTS)
すべてのAPI通信を HTTPS を使用して暗号化します。これにより、通信内容が第三者に漏れたり改竄されたりするリスクを防ぎます。
クライアントが非暗号化通信のHTTPをリクエストした際、強制的にHTTPSへ切り替えるHTTP Strict Transport Security (HSTS)をレスポンスヘッダーに含めることで、リクエスタにHTTPS通信を強制化させることができます。
CORS (Cross-Origin Resource Sharing)の有効化 とOPTIONSメソッド
本来ドメインをまたいだ通信を許可するためのものですが、クラウドサービスを利用する場合、クラウドベンダーが出力したクラウドベンダー独自ドメインと、サービス提供者専用ドメインが混在するため必然的に必須となる設定です。以下のようにサーバへのリクエストを出すクライアント側を制御することが可能です。
設定例:
add_header 'Access-Control-Allow-Origin' 'https://domainA.com'; # 特定のドメインのみ許可
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # 許可するHTTPメソッド
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization'; # 許可するヘッダー
これにより https://domainA.comからの通信に対してGET, POST, OPTIONSのみのリクエストを受け付けるよう制限することが可能です。この場合、リクエストの際付与可能なヘッダーも'Access-Control-Allow-Headers' 'Content-Type, Authorization'に限定できます。
尚CORS仕様上OPTIONSメソッドの受付けが必ず必要になります。通常使用しないメソッドなので設定で禁止しがちですので注意が必要です。
Content Security Policy
リクエスタからのAPI呼び出しに対するレスポンスHTTPヘッダ、もしくはブラウザに読み込ませるHTML内に指定しておくことで以下のような制御が可能です。
- 実行可能なJavaScriptファイルの読み込み元ドメイン制限
- 読み込み可能なCSSファイルの読み込み元ドメイン制限
- スクリプトが通信可能なドメインの制限
- 違反時の報告先(ブラウザが自動で報告します)
設定例:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://trusted-scripts.com;
style-src 'self' https://trusted-styles.com;
こうすることでスクリプトが万が一改竄されていたとしても、ブラウザが不正なスクリプトを実行したり、情報を怪しいサイトにバックグランドでPOSTしていた、という動作を防ぐことが可能です。
X-Frame-Optionsという 他のページでiframeとして埋め込こまれ、別のサイトが勝手にウェブサイトの内容をあたかも自分のサイトであるように表示させることを防ぐHTTPヘッダも、このCSPを利用する方式が現在は推奨されています。
https://developer.mozilla.org/ja/docs/Web/HTTP/Reference/Headers/X-Frame-Options
その他セキュリティヘッダ
主に利用されるのは以下のようなものです。リクエスタからのAPI呼び出しに対するレスポンスに以下のヘッダを付与することで不正なサイトの呼び出しを制御できます。
・ X-Content-Type-Options: MIMEタイプのスニッフィングを防ぐ