Webデベロッパのためのセキュリティ・チェックリスト


安全で堅牢なWebアプリケーションをクラウドで開発するのは非常に困難です。それを簡単だと思っているような人は、例えばとんでもない頭脳をお持ちというなら別ですが、遠からず痛い目を見ることになるでしょう。

もしMVP(Minimal Viable Product:必要最低限の機能を備えた製品)のコンセプトを鵜呑みにして、有益かつ安全な製品を1ヶ月で作成できると考えているようなら、プロトタイプを立ち上げる前に一度考え直した方がいいと思います。以下に挙げたチェックリストをご覧いただければ、セキュリティに関するクリティカルな問題の多くをスキップしていることが分かるはずです。あるいは少なくとも、潜在的なユーザに対しては誠実であるように心がけ、製品が完全ではないこと、そしてセキュリティが不十分な製品を提供していることを伝えるようにしてください。

このチェックリストはシンプルなもので、決して完全とは言えませんが、14年以上にわたるWebアプリケーション開発の経験の中で、私自身が痛切に学んだ重要な項目が含まれています。皆さんがWebアプリケーションを作成する際、これらの項目を思い出していただければ幸いです。

また、もしこのリストに加えられそうな項目がありましたら、ぜひコメントでお知らせください。

データベース

  • アクセストークン、電子メールアドレス、支払明細などの機密データやユーザ識別データに対しては、可能な限り暗号化を使用する(これによりクエリが完全一致のルックアップに制限されます)。
  • データベースが低コストのリソース暗号化(AWS Auroraなど)をサポートしている場合は、それを有効にしてディスク上のデータを保護する。バックアップ用の全データも暗号化して保存する。
  • データベースにアクセスするためのユーザアカウントの権限は最小限にする。データベースのルートアカウントは使用せず、使われていないアカウントやリスクが高いパスワードのアカウントをチェックする。
  • 専用の目的のために設計されたキーストアを使用して秘密を保管し、配布する。アプリケーション内へのハードコーディングは避ける。
  • SQLのプリペアドステートメントのみを使用してSQLインジェクションを完全に防止する。例えばnpmを使用している場合、npm-mysqlは使用せず、プリペアドステートメントに対応したnpm-mysql2を使用する。

開発

  • O/Sやライブラリ、パッケージにおいて、製品版にプッシュされる全てのバージョンにおいて、ソフトウェアに含まれる全コンポーネントの脆弱性をスキャンする。この処理はCI-CDプロセスに組み込まれて自動化されるべきである。
  • 開発システムを、本番システムで使用するものと同等のセキュリティで保護する。安全で隔離された開発システムによってソフトウェアを構築する。

認証

  • bcryptなどの適切な暗号文を使用して、全てのパスワードがハッシュされていることを確認する。独自に暗号文を書いたりせず、良好なランダムデータで正しく暗号文を初期化する。
  • ログインパスワードや忘れられたパスワード、その他のパスワードをリセットする際には、最良の実践方法と実績のあるコンポーネントを使用する。(全ての状況で正しく適用できるかが未知数のため)独自に開発はしない。
  • ユーザに対して、ランダムで長いパスワードの作成を促すような、シンプルで適切なパスワードルールを実装する。
  • 全てのサービスプロバイダへのログインにマルチファクタ認証を使用する。

サービス拒否攻撃からの保護

  • APIに対するDoS攻撃でサイトに不具合が生じないことを確認する。少なくとも、ログインやトークン生成ルーチンなどの認証に関するAPIや遅いAPIのパスには、レートリミッタを使用する。バックエンドサービスをDoS攻撃から保護するため、フロントエンドのAPIにCAPTCHAを検討する。
  • ユーザからの送信データ(submit data)およびリクエストのサイズと構造にサニティーチェックを適用する。
  • CloudFlareのようなグローバルキャッシュのプロキシサービスを介して、分散型サービス妨害攻撃(DDoS)の軽減を検討する。これはDDoS攻撃を受けた際に有効な他、DNSルックアップとしても機能する。

Webトラフィック

  • ログインフォームや応答だけでなく、サイト全体にTLSを使用する。ログインフォームだけのためにTLSを使用しない。移行時に、strict-transport-securityヘッダを使用して、全てのリクエストに対してHTTPSを強制する。
  • CookieはhttpOnlyを使用してセキュリティを確保し、パスとドメインでスコープを設定する。
  • CSP(Content Security Policy)を使用して、危険なバックドアを許可しない(設定は骨が折れるものの、その価値はあります)。CDNのコンテンツにはCSPのSubresource Integrityを使用する。
  • クライアントの応答には、X-Frame-Option、X-XSS-Protectionヘッダを使用する。
  • HSTSの応答を使用して、TLSオンリーのアクセスを強制する。全てのHTTP要求を、バックアップとしてサーバ上のHTTPSにリダイレクトする。
  • 全てのフォームでCSRFトークンを使用する。また全ての新規ブラウザに対して新しいSame-Site Cookieの応答ヘッダを使用し、CSRFを一度に固定する。

API

  • 公開されているAPIでリソースを列挙(enumerable)できないようにする。
  • ユーザがAPIを使用する際は、完全に認証され、適切に権限が与えられていることを確認する。
  • APIでカナリアのチェック(canary checking)を行い、攻撃を示す不正または異常な要求を検出する。

検証とエンコーディング

  • ユーザへの迅速なフィードバックのためにクライアント側での入力検証を行うが、全面的には信用はしない。表示前に常にユーザの入力を検証してエンコードを行う。
  • サーバ上のホワイトリストを使用して、ユーザが入力した全てを検証する。応答にユーザのコンテンツを直接挿入はしない。また、SQLステートメントまたは他のサーバ側のロジックで信頼されないユーザの入力は使用しない。

クラウド設定

  • 全てのサービスで開いているポートが最低限であることを確認する。隠すことによるセキュリティでは基本的には保護されない。非標準ポートの使用は攻撃者に対する防御となり得る。
  • パブリックネットワーク上に表示されないプライベートVPCのバックエンドデータベースおよびサービスをホスティングする。AWSセキュリティグループを設定する時、あるいはピアのVPCを設定する時は、誤ってサービスを一般に公開する可能性のあるため十分に注意する。
  • 個別のVPCおよびピアVPCで論理サービスを分離し、サービス間の通信を提供する。
  • 全てのサービスで、最小限のIPアドレスからのデータのみを受け入れるようにする。
  • 発信IPとポートトラフィックを制限して、APT攻撃と”bot攻撃”を最小限に抑える。
  • ルート認証情報ではなくAWS IAMロールを常に使用する。
  • 全てのオペレータおよび開発者に対して、最小限のアクセス権を用いる。
  • スケジュールに従って、定期的にパスワードとアクセスキーを変更する。

インフラ基盤

  • ダウンタイムなしでアップグレードの実行ができることを確認する。完全に自動化された形態でソフトウェアを迅速に更新できることを確認する。
  • クラウドコンソールではなく、Terraformなどのツールを使用して全てのインフラストラクチャを作成する。インフラストラクチャは”コード”として定義し、1回の操作で再作成できるようにする。クラウド内で手作業によって作成されたリソースに関しては容赦なくTerraformを通じて設定を監査する。
  • 全てのサービスで、 集中ログサービスを使用する。ログへのアクセス、またはログの取得にSSHは使用しない。
  • 診断が1回限りである場合を除き、サービスではSSHを使用しない(SSHを定期的に使用するということは、一般的に重要なタスクが自動化されていないということを意味します)。
  • いかなる場合でも、AWSサービスグループ上で恒久的にポート22を開放しない。SSHを使用する必要がある場合は、公開鍵認証のみ使用し、パスワード認証は使用しない。
  • long-lived(長命の)サーバの代わりにImmutableな(不変の)ホストを作成して、パッチの適用やアップグレードを行う(Immutable infrastructure can be dramatically more secure(不変のインフラストラクチャはより安全)を参照)。
  • 侵入検知システムを使用してAPT攻撃を最小限に抑える。

オペレーション

  • 未使用のサービスやサーバは停止する(停止中のサーバが最も安全です)。

テスト

  • 設計と実装を監査する。
  • 侵入テストを行う。自分でハックするのみならず、第三者にも依頼する。

訓練

  • ソーシャルエンジニアリングのセキュリティで使用される技術やその危険性についてスタッフ(特に主任クラス)を訓練する。

最後に、計画立案

  • セキュリティ保護の対象となる脅威モデルを用意し、潜在的な脅威と対処法の優先順位を設定する。
  • 将来的な予防策として、セキュリティの問題が発生した際に実践しうる対処プランを準備する。

サイトのセキュリティをより確実にしたい場合は、ぜひSenseDeepのシンプルなクラウドセキュリティをお試しください。