X

OWASP Secure Coding Practices – Quick Reference Guide

(Last Updated On: )

OWASPのガイドラインはPCI DSSでも参照するように指定されているセキュリティガイドラインです。その中でも比較的簡潔かつ体系的にセキュアプログラミングを解説した資料がOWASP Secure Coding Practices – Quick Reference Guide (v2) です。

日本語訳がないようなので一部未訳ですが訳しました。CC-BY-SAライセンスです。クリエイティブコモンズライセンスに従って自由に配布できます。

チェックリスト形式になっているので、自分のコーディング/開発スタイルがどの程度適合しているのか、簡単にチェックできるようになっています。コーディングスタイルのみでなく、運用はシステム構成に関連する物も含まれています。私が解説/紹介しているセキュリティ対策を行っている開発チームであればこれらの殆どに適合しているはずです。どのくらい適合していたでしょうか?

イントロダクションでは、開発者に対して少々厳しいことが書いてあります。

この技術的不可知論文書は一般的なセキュアコーディングを実践に必要な要素をソフトウェア開発ライフサイクルに統合可能なチェックリストとして定義します。

「技術的不可知論文書」(不可知論:物事の本質は人には認識することが不可能である、とする立場のこと ※ )としているのは、この文書が取り扱うセキュアコーディングの本質が理解されていない、理解されることがない、と嘆いていることを意味します。セキュアコーディングの本質の解説は諦めて作ったチェックリストであることを示唆しています。私も同じ感覚を共有しています。興味がある方はぜひ以下の参考資料を参照してください。原理と原則を知った方が応用範囲が広がります。

正確な直訳より分かり易さを優先しました。見直しをする時間まではありませんでした。誤り、誤解を招く訳などの指摘を歓迎します。

※ Agnostic(不可知論)について: このガイドは2010年に公開された文書です。最近、agnosticは「〜に依存しない」「〜に関わらず」「〜を問わず」「汎用的」「プラガブル」「詳しく知らなくても使える」といったコンテクストで割と一般的なIT用語として利用されています。2010年頃は哲学的意味が強かったと思いますが、現在は先に書いたような意味で使われているケースが多くあります。

参考資料:

OWASP セキュアコーディングプラクティス – クイックリファレンスガイド

著作権とライセンス

この文書はクリエイティブコモンズアトリビューションシェアーアライク(CC-BY-SA)3.0ライセンスで配布されています。この文書のどのような再利用または配布にはこのライセンスを適用しなければならないことを明示しなければなりません。

http://creativecommons.org/licenses/by-sa/3.0/

目次

  1. イントロダクション
  2. ソフトウェアセキュリティとリスク原則の概要
  3. セキュアコーディング実践チェックリスト
    1. 入力バリデーション
    2. 出力エンコーディング
    3. 認証とパスワード管理
    4. セッション管理
    5. アクセス制御
    6. 暗号の取り扱い
    7. エラー処理とログ
    8. データ保護
    9. 通信セキュリティ
    10. システム設定
    11. データベース管理
    12. ファイル管理
    13. メモリ管理
    14. 一般的コーディング実践
  4. 付録A
    1. 外部リファレンス
  5. 付録B – 用語集

イントロダクション

この技術的不可知論(訳注:物事の本質は人には認識することが不可能である、とする立場のこと)文書は一般的なセキュアコーディングを実践に必要な要素をソフトウェア開発ライフサイクルに統合可能なチェックリストとして定義します。これらを実践することにより最も多いソフトウェア脆弱性のほとんどとを緩和できます。

一般的にソフトウェアが完成した後で問題を修正するより、セキュリティ事件によって発生するコストを除いても、最初からセキュアなソフトウェアを開発するコストの方が遥かに少ないです。

攻撃者が攻撃目標をアプリケーション層に定めたことにより、重要なソフトウェア資源の安全性確保は以前にも増して重要になっています。2009年のSANS調査では、インターネット上で見られる攻撃全体の60%はWebアプリケーションに対するものだった、としています。

このガイドを適用する場合、開発チームはセキュアソフトウェア開発ライフサイクルと開発者の知識レベルの成熟度を知ることからはじめなければなりません。(訳注:セキュリティ対策の用語定義基本的なセキュリティ原則 を知らないようではこのガイドを理解できません)この文書は具体的な実装方法を解説していません。このため開発者が事前に実装方法を習得しているか、必要なガイダンスを提供する十分なリソースが必要です。このガイドは開発者が深いセキュリティ脆弱性と攻撃に対する理解を持たなくてもプログラミングに必要な要素を実践できるようになっています。しかしながら、開発メンバーの中にはシステム全体の設計と実装が安全であることを責任が持てるよう、適切なトレーニング、ツールとリソースを利用できる者が居なければなりません。

セクションタイトルを含むこの文書の重要な用語はイタリック体で表記され付録Bの用語集で定義されています。(訳注:この訳はこの表記には対応していません)

安全なソフトウェア開発フレームワークのガイドラインはこの文書の範囲を超えています。以下の一般的なプラクティスとリソースを推奨します。

ソフトウェアセキュリティとリスク原則の概要

安全なソフトウェア構築には基本的なセキュリティ原則の理解が欠かせません。包括的なセキュリティ原則の解説はこの文書の範囲を超えますが、概要を簡単に説明します。

ソフトウェアセキュリティの目的はビジネスの成功に必要な情報リソースの機密性、統合性と可用性を維持することにあります。この目的はセキュリティ対策(Security Control)の実装により達成できます。このガイドは一般的なソフトウェア脆弱性を発生を緩和する技術的なセキュリティ対策に焦点をあてています。主にWebアプリケーションとその基盤に焦点をあてていますが、ほとんどの事項はどのようなソフトウェア開発にも適用できます。

ソフトウェアを利用することにより発生する許容できないリスクからビジネスを守るには、リスクとはどのような物か理解する必要があります。リスクとはビジネスの成功の脅威となる要素の複合体です。概念的には、攻撃者(Threat Agent)が攻撃可能な脆弱性(Vulnerability)を持つシステムを攻撃し損害(Impact)を与える、と説明できます。この説明は抽象的に感じるかも知れません。車上荒らし(攻撃者)が駐車場(システム)でドアをロックしていない(脆弱性)車を探し、見つけたらドアを開け(攻撃)、車の中にあるものを盗む(損害)と考えると解りやすいでしょう。これら全ての要素がセキュアなソフトウェア開発には欠かせません。

ソフトウェアの開発チームとソフトウェアの攻撃者のアプローチには根本的な違いがあります。ソフトウェア開発者はアプリケーションに何をさせようとしているのか、を考えます。言葉を変えると、開発者は定義された文書化された機能要求やユースケースに基き特定のタスクを実行するようアプリケーションを設計します。それと異り、攻撃者はアプリケーションにどのようなことができるように作られているか、”明示的に禁止されていないが許されている物”に対する操作に関心を持ちます。この違いに対応するため、この文書の幾つかの要素、セキュリティ要求(Security Requirement)と不正利用ケース(Abuse Case)、は開発の初期段階で適用される必要があります。このガイドは高いレベルのセキュリティ要求と多くの一般的な不正利用ケースのシナリオを認識できるよう考慮されています。

Web開発チームが、クライアント側の入力バリデーションや隠しフィールドとインターフェースによる制御(ドロップダウンリスト、ラジオボタンなど)はセキュリティ的にはメリットがあっても、僅かしかないことを認識することが重要です。攻撃者はクライアント側でWebプロキシー(OWASPのWebScrabやBurpなど)やネットワークのパケット取得ツール(WireSharkなど)を使い通信を分析し、インターフェースを完全にバイパスすることが可能です。それに加え、Flash、Javaアプレットとその他のクライアント側のオブジェクトは逆コンパイルでき問題を分析可能です。

ソフトウェアセキュリティ問題はソフトウェア開発ライフサイクルのどの段階でも導入されます。

  • 事前に把握すべきセキュリティ要求を識別しない
  • 論理的誤りを持つ発想の設計
  • 劣ったコーディングプラクティスによる技術的な脆弱性の導入
  • 不適切なソフトウェアのデプロイ
  • メンテナンスまたはアップグレードによる問題の導入

さらに、ソフトウェア脆弱性はソフトウェアの範囲を越えた領域でも発生すること理解しなければなりません。ソフトウェアの性質によって、脆弱性や基盤によって、攻撃成功は次のどれかまたは全てに影響します。

  • ソフトウェアと関連する情報
  • 関連するサーバーのOS
  • データベースサーバー
  • 共有環境の他のアプリケーション
  • ユーザーのシステム
  • ユーザーが利用するその他ソフトウェア

セキュアコーディング実践チェックリスト

入力バリデーション

  • 信頼するシステム全てが入力バリデーションを実施するよう指揮する
    (訳注:自分のアプリケーションだけでなく、関連するシステム全てが入力バリデーションを行っていることを確認する。入力バリデーションを行っていないシステムは危険なシステムとして注意する)
  • 全てのデータの発生元を識別し、信用できるものとできない物に分類する。全ての信頼できないデータはバリデーションする。(例:データベース、ファイル、その他)
  • アプリケーションは集中した入力バリデーションライブラリを持たなければならない
  • 全ての入力元のデータに対して、UTF-8など、適切な文字エンコーディングを指定する
  • バリデーションの前に共通の文字エンコーディングに変換する(Canonicalize)
  • 全ての入力バリデーション失敗は拒否しなければならない
  • システムが拡張UTF-8文字セットをサポートするか確認し、サポートする場合はUTF-8のデコードが終わってからバリデーションする
  • クライアントからのデータは全てバリデーションする。全てのパラメータ、URLやHTTPヘッダー(Cookieの名前と値など)の内容などが含まれる。JavaScript、Flashや他の埋め込みコードからの自動送信が含まれることに注意する。
  • リクエストヘッダー、レスポンスヘッダーがASCII文字だけが含まれていることを確認する
  • リダイレクトからのでデータをバリデーションする(バリデーション無しでは攻撃者は攻撃用データをリダイレクトターゲットに直接送信可能になる場合があり、リダイレクト前のアプリケーションロジックやあらゆる入力バリデーションを回避可能になる)
  • 期待するデータ型であることをバリデーションする
  • データ範囲をバリデーションする
  • データ長をバリデーションする
  • 全ての入力に対して、可能な限り許可する文字を”ホワイト”リストでバリデーションする
  • 入力に潜在的に危険な文字を許可しなればならない場合、出力エンコーディング、特定のタスクに対して安全なAPIなどの他のセキュリティ対策を実装し、これらのデータ利用をアプリケーション全体で把握する。よくある危険な文字には < > ” ‘ % ( ) & + \ \’ \” などがある(訳注: ” “(半角スペース)も危険となる場合がある。次にあるように改行を含む制御文字も基本的に危険)
  • もし標準のバリデーションライブラリが以下の入力に対応できない場合、以下の物は個別に確認しなければならない
    • ヌル文字(%00)をチェックする
    • 改行文字(%0d, %0a, \r, \n)
    • パスを変更する文字列(../ および ..\)をチェックする。UTF-8の拡張文字セットがサポートされている場合、%c0%ae%c0%ae/ など別形式の形もチェックする(Canonicalize(正規化)を利用し重複エンコーディングや他の不明瞭化攻撃に対応する)
      (訳注:../ や ..\ を取り除きなさい、ではありません。単純に取り除くだけだと簡単に攻撃できます。../を取り除く場合、…/…//がどうなるか考えると解ります)

出力エンコーディング

  • 信頼するシステムの文字エンコーディングを確実の制御/管理する(例:サーバーなど)
  • それぞれの出力に対して標準、テストされた出力プログラムを利用して出力をエンコードする
    (訳注:OWASPでは”エスケープ”を拡張した概念である”エンコード”という用語を使っています。エスケープする、との理解でも取り敢えずは構いません)
  • コンテクストに適合した出力エンコーディングを全ての出力データに適用する。これはアプリケーションの信頼境界線に外にあるクライアントなどに適用します。例えば、HTMLエンティティエンコードがあります。しかし、HTMLエンティティエンコードは全てのケースに適用できません。
    (訳注:出力をエスケープ(エンコード)する場合は、出力する先のコンテクストを意識したエスケープを行わないと意味がありません。HTMLテキスト、HTML属性の値、HTML中のJavaScript、CSSなどがコンテクストを意識したエスケープが必要な例です)
  • 全ての文字をエンコードする。例外は出力先にとって確実に安全な場合のみとする
    (訳注:出力を行う同じ関数内でプログラマが静的に設定する変数などが、安全なデータの例です)
  • SQL、XML、LDAPなど信頼できないシステム対する出力全て、コンテクストに応じてサニタイズする。
    (訳注:データの種類や出力先のコンテクストによってはエンコード(エスケープ)が不可能な場合がある。この場合、出力をサニタイズ(無害化)してから出力する。SQLの識別子、SQL語句などが適用例です。LDAPのAPIにはエスケープAPIが無い物があります。LDAPクエリには2種類のエスケープ可能コンテクスト、search filterとDN – distinguished name、があります。)
  • OSコマンドを利用する場合、全ての信頼できないデータはサニタイズする
    (訳注:全てのOS、シェル、コマンド引数パーサーに対して確実に安全にエスケープする標準的な方法はありません。このため確実に安全な文字列のみ出力するようにします)

認証とパスワード管理

  • 全てのページ、リソースに対して認証を要求し、公開する物のみを例外とする
    (訳注:全てのリソースにデフォルトで認証を要求し、公開する物のみをホワイトリストとして公開する)
  • 全ての認証制御は信頼されたシステムで行わなければならない(例:サーバー)
    (訳注:クライアント側の認証処理は役立たない)
  • 標準、テストされた認証サービスを可能な限り利用する
  • 認証の集中管理を実装する。外部の認証サービスライブラリを利用する場合も含む
  • 認証ロジックと要求されているリソースを分離し、集中化された認証サービスへのリダイレクトを利用する
  • 全ての認証制御は安全に失敗しなければならない
    (訳注:例えば、認証は全ての処理の前に行う、不正なアクセスは記録する、パスワードを変更する場合にシステムが許容しない長さのパスワードの場合はエラーにして勝手に切り詰めない、など)
  • 全ての認証管理とアカウント管理機能は少なくとも主たる認証メカニズムと同程度に安全にする
    (訳注:管理用インターフェースはIPアドレス制限だけ、公開エリアと異りHTTP認証だけにするなど)
  • アプリケーションが認証データを保存する場合、暗号理論的に強いハッシュ関数を用い、ソルトと一緒にパスワード保存し、データベーステーブル/ファイルに保存されたパスワード/キーはそのアプリケーションだけが書き込めるようにする(MD5はできる限り利用しない)
    (訳注:現在はSHA1でさえ利用すべきではない。SHA3が利用可能な場合、SHA3を利用する)
  • パスワードのハッシュは信頼できるシステムで行う(例:サーバーで行う)
  • 認証データは全てのデータを取得してからバリデーションを行う。特にシーケンシャル認証を実装する場合には必須
    (訳注:シーケンシャル認証とは認証を1つのリクエスト/ページで行うのではなく、一連のページに必要な認証データを入力し認証する仕組みのことです)
  • 認証失敗時のレスポンスにはどの認証データが間違っていたのかを示唆する情報を含めない。例えば、”不正なユーザー名です”や”不正なパスワードです”とは表示せず、単に”ユーザー名かパスワードが不正です”と表示する。エラー時のレスポンスは表示上、コード上(HTML)ともに全く同一でなければならない
  • 機密データを取り扱う外部システムとの接続には認証の仕組みを利用する
  • 外部サービスにアクセスするための認証用のクレデンシャルは保護された信頼できるシステムに暗号化して保存する(例:サーバーに保存する)ソースコードは安全な保存場所ではない
  • 認証用のクレデンシャルはHTTPのPOSTメソッドのみを用いて送信する
  • 恒久的なパスワードは暗号化された接続または暗号化したデータ、例えば暗号化メール、としてのみ送信する。メールによるパスワードリセット用の一時的なパスワードは例外
  • セキュリティポリシーまたは基準などに従い、複雑なパスワードの利用を強制する。認証クレデンシャルは利用される環境において一般的な脅威と攻撃に十分対応できる物でなければならない。(例:アルファベット、数字および記号の利用を強制するなど)
  • セキュリティポリシーまたは基準などに従い、パスワードの長さを強制する。8文字のパスワードがよく利用されるが、16文字以上が好ましい。または複数の単語を利用するパスフレーズの導入を検討する
    (訳注:ユーザーにとって覚えやすい複数の単語を組み合わせて作ったパスフレーズでも、単語数が十分であればランダムパスワードと同等以上の安全性である、とする研究がある)
  • パスワード入力用のフィールドはユーザー画面上から内容が見えないようにする。(例:Webフォームの場合、inputの種別に”password”を利用する)
  • 決まった回数(5回が一般的)のログイン失敗でアカウントの無効化を行う。パスワードを推測するブルートフォース攻撃を諦めさせる為に十分な時間を設定する。ただし、サービス不能攻撃が可能になるほど長い時間は設定しない。
  • パスワードリセットおよび変更操作はアカウント作成/認証と同じレベルの制御を要求する
  • パスワードリセットの質問は十分にランダムとなる回答が得られる質問でなければならない。(例:”好きな本”は悪い例。”聖書”と答えるユーザーが多い)
    (訳注:私としてはパスワードリセットの秘密の質問の利用はお勧めしません。これはメールアドレスや携帯電話などが利用できない環境を想定した仕組みであまり安全とは言えません)
  • メールを利用したパスワードリセットを実装する場合、既に登録済のメールアドレスにのみ一時的なパスワード/URLを送信する
  • 一時的なパスワード/URLは短い有効期間を持たなくてはならない
  • 一時的なパスワードは次の利用でパスワードを変更するよう強制する
  • パスワードのリセットが行われた場合、ユーザーに通知する
  • 同じパスワードの再利用は禁止する
  • パスワードの再変更には最低1日を要求し、パスワード再利用の攻撃を防止する
  • セキュリティポリシーまたは基準などに従い、パスワードの変更を要求する。重要なシステムの場合はより頻繁な変更を必要とされる。リセットする間隔は管理者が制御できなければならない
    (訳注:パスワードの強度が十分に強く他のシステムと共有していない場合、頻繁な変更がリスクに成り得ます。頻繁すぎる更新はユーザーが脆弱なパスワードを設定する原因になります。特にセキュリティリテラシーの低いユーザーにはこの傾向が顕著である点に注意が必要です)
  • パスワードをフィールドでは”自動入力機能”を無効にする
    (訳注:このプラクティスには異論があります。私はブラウザにサービス毎に完全にランダムなパスワードを記憶させています。何十文字もあるランダム文字列を記憶/入力するのは無理があります。しかし、共有システムの存在を考慮するとこの要求は妥当です)
  • 最後の利用時間(ログイン成功、ログイン失敗)は次のログイン成功時にユーザーに知らせなければならない
  • 同じパスワードを利用し、複数のアカウントに対してログインを試行する攻撃を検出する仕組みを構築する。この攻撃はIDが知られていたり、簡単に推測できる場合のアカウントロック機構を回避する攻撃パターンとして知られている。
    (訳注:JALのマイレージバンクが攻撃されたのはまさにこのパターンです。このガイドを読み実践していたら避けられた攻撃でした)
  • ベンダーが設定したデフォルトパスワード、IDは全て変更する、またはこれらのアカウントを無効にする
  • 重要な操作を行う場合、ユーザーに再認証を要求する
  • 重要なアカウント、トランザクションには多要素認証を利用する
    (訳注:スマートフォンの普及により多要素認証の敷居は低くなっています。一般的なシステムでも多要素認証をお勧めします)
  • 認証に外部ライブラリを利用する場合、不正なコードが含まれていないか慎重に検証/検査する

セッション管理

  • サーバーまたはフレームワークのセッション管理を利用する。アプリケーションはこれらのセッション管理システムが生成したIDのみで妥当だと識別しなければならない。
    (訳注:PHPの場合、session.use_strict_mode=Onで利用する必要があります。この機能は私が実装しました。しかしPHPのセッションには他の問題もあります。必ずしも提供されたセッション管理機構が理想的とは限りませんが、独自に実装するよりは提供されたセッション管理機構を安全な設定で使う方が良いでしょう。より安全に利用するために独自に拡張することはお勧めします。タイムスタンプを利用した有効期限管理が必要です)
  • セッションIDの生成は常に信頼できるシステム上で行う(例:アプリが動作するサーバーで生成する)
  • セッション管理機構は十分にランダムなIDが生成可能であるよう、緻密に検証されたアルゴリズムを利用する
  • 認証済みセッション用のクッキーにはサイトにとって適切な範囲に制限するドメインとパス属性を設定しなければならない
    (訳注:これは特に共有環境で重要です)
  • ログアウト機能は関連するセッション/接続を完全に破棄させなければならない
  • ログアウト機能は全ての認証済みページで利用できなければならない
  • リスクとビジネス的な機能のバランスを考えて、セッションの有効期限(タイムアウト)はできる限り短く設定する。ほとんどの場合、数時間以上のセッションを許可してはならない
    (訳注:自動ログイン機能は長いセッションで実装してはいけません)
  • 継続的なログインを許可せず、セッションがアクティブでも定期的にセッションを破棄する。特に多数のサービスに接続するアプリケーションや重要なシステムではこのような処理が必要です。破棄までの時間はビジネス要求を満し、ユーザーからの苦情を緩和するためにユーザーが十分な情報を得られるようにする
  • もしログイン前のセッションがある場合、そのセッションは破棄しログイン成功時に新しいセッションを作らなければならない
    (訳注:PHPの場合、session_regenerate_id()関数がそれにあたります。しかし、この関数には問題があり、ここ数年間改修に取り組んでいますがまだマージにまで至っていません。古いセッションに対してタイムスタンプを利用した有効期限管理が必要です)
  • 再認証時には必ず新しいセッションIDを生成しなければならない
  • 同じユーザーIDでの同時接続を許さない
    (訳注:これは多くの一般的Webサイトでは難しいと思います。しかし、金融機関などのサイトではこのような制限は必要です)
  • セッションIDをURL、エラーメッセージ、ログに記載しない。セッションIDはHTTPのクッキーヘッダでのみ利用する。例えば、セッションIDをGETメソッドのパラメータとして利用してはならない
  • サーバー側のセッションデータは許可のないユーザー/アプリケーションからアクセスできないよう適切なアクセス制御をサーバー上で実装し保護する
  • 定期的に新しいセッションIDを生成し、古いセッションIDを破棄する(この操作は元のセッションIDが漏洩した場合など、セッションハイジャックの緩和策となる)
    (訳注:セッションIDを盗んだ攻撃者が有効なセッションIDを取得する場合もありますが、正当なユーザーも突然ログアウトした状態になるため、セッションハイジャックに気づく切っ掛けになる。古いセッションは即座に削除しない。タイムスタンプを利用した有効期限管理が必要です)
  • HTTPからHTTPSに接続が変更された場合、新しいセッションIDを生成する。これは認証時に発生する場合がある。アプリケーション内ではHTTPとHTTPSを切り換えることなく、常にHTTPSを利用することが望ましい
  • サーバー側での機密データの取り扱いにセッションを利用する。例えば、アカウント管理などにはセッション単位に保存された強いランダムトークン/パラメータを利用する。この方法でCSRF攻撃を防止できる
  • サーバー側での非常に機密性の高いデータの取り扱いや操作にセッションを利用し、セッション単位ではなく、リクエスト単位、強いランダムトークン/パラメータを利用する
  • TLS(HTTPS)接続のクッキーには”secure”属性を指定する
  • HttpOnly属性をクッキーに指定する。ただし、クライアント側のスクリプトがクッキーの値を参照/変更する必要がある場合は除く
    (訳注:セッションID管理用のクッキーにはHttpOnly属性を常に設定することをお勧めします)

アクセス制御

  • 信用可能なシステムオブジェクトのみ利用する(例:サーバー側のセッションオブジェクトのみを認証の判断に利用する)
  • 単一かつシステム全体のアクセス許可コンポーネントを利用する。これには外部認証サービスを行うライブラリも含める
  • アクセス制御は安全に失敗しなければならない
  • アプリケーションがセキュリティ設定情報にアクセスできない場合、全てのアクセスを拒否する
  • 全てのリクエストに対して認可の制御(アクセス制御)を強制する。これにはサーバーサイドスクリプト、AJAXやFlashのリクエストも含める
  • 特権機能と他のアプリケーション機能を分離する
  • ファイルや他のリソースへのアクセスを制限する。アプリケーションが直接制御しないファイルを含め、許可されたユーザーのみがアクセスできるようにする
  • 許可されたユーザーのみが保護されたURLにアクセスできるよう制限する
  • 許可されたユーザーのみが保護された機能にアクセスできるよう制限する
  • 許可されたユーザーのみが直接オブジェクトを参照できるよう制限する
  • 許可されたユーザーのみがサービスにアクセスできるよう制限する
  • 許可されたユーザーのみがアプリケーションデータにアクセスできるよう制限する
  • 許可されたユーザーのみがユーザーおよび属性データおよびポリシー情報にアクセスできるよう制限する
  • 許可されたユーザーのみがセキュリティ関連の設定情報にアクセスできるよう制限する
  • サーバー側の実装とプレゼンテーションレイヤーの表示はアクセス制御ルールと一致しなければならない
  • クライアントサイドに状態データを保存しなければならない場合、暗号を用い、改竄を防ぐための完全性チェックをサーバー側で行う
  • アプリケーションロジック問題はビジネスルールに適合するよう強制する
    (訳注:エラー発生時の対処はビジネスルールとして定義されている。例えば、ゲームなどの場合はデータ取得エラーや計算エラーは無視して処理を進め、会計関連の場合は致命的エラーとして対処するなど)
  • 一定時間の間に単一ユーザーまたはデバイスが実行可能なトランザクションを制限する。上限のトランザクション数/間隔は実際のビジネス要求を上回っていなければならないが、自動的な攻撃の効果を無くす程度に低くなけばならない。
  • “REFERER”ヘッダは追加のチェックとしてのみ利用する。REFERERヘッダは改竄可能であり、REFERERのみで認証することは決して行わない。
  • 長い時間のセッションが許可されている場合、定期的にユーザーの認可情報をチェックし、権限が変更されていないか再バリデーションし、変更されている場合はユーザーをログアウトさせ、再認証させる
  • アカウント監査機能を実装し、未使用アカウントの無効化を行う(例:例えば、アカウントのパスワード期限が失効してから30日後から無効とするなど)
  • アプリケーションは許可の取り消しなどの処理の為にアカウントの無効化とセッションの廃棄をサポートしなければならない。(例:役割の変更、雇用状態の変化、ビジネスプロセスの変化、など)
  • サービスアカウントまたは外部へ/内部への接続を行うアカウントは必要最小限の権限のみ持たせる
  • アプリケーションのビジネスルールをドキュメント化し、システムにアクセスできるデータ種別やアクセス許可の分類/プロセスが適切に提供され制御できる、アクセス制御ポリシーを作成する。これにはデータおよびシステムリソースへのアクセス要求を識別し含める。

暗号の取り扱い

  • アプリケーションユーザーから秘密保護目的に利用する全ての暗号機能は必ず信頼できるシステム(例:サーバー)上で利用する
  • マスターとなる秘密鍵などを許可のないアクセスから守る
  • 暗号モジュールは安全に失敗しなければならない
  • ランダム値が推測されてはならない場合、全てのランダム数値、ランダムファイル名、ランダムGUIDとランダム文字列は暗号モジュールの検証されたランダムナンバー生成器(RNG)を利用する
  • アプリケーションが利用する暗号モジュールはFIPS 140-2に適合するか、同等の標準に適合したものを利用する(参照:http://csrc.nist.gov/groups/STM/cmvp/validation.html
  • どのように暗号鍵を管理するか、利用ポリシーとプロセスを確立し利用する

エラー処理とログ

  • エラー表示に秘密の情報を含めない。これにはシステム情報、セッションID、アカウント情報などが含まれる
  • デバッグ情報、スタックトレース情報を含めないエラーハンドラーを利用する
    (訳注:当然ですが開発時にこれらの情報を含めることには問題はない)
  • 一般的なエラーメッセージにカスタムエラーページを実装する
    (訳注:フレームワークやWebサーバーのエラーメッセージやエラーページを利用しない)
  • アプリケーションはサーバーの設定を頼りにせず、アプリケーションのエラーを処理する
  • エラーが発生した場合、適切に割り当て済みメモリを解放する
  • セキュリティ制御に関連するエラー処理ロジックはデフォルトでアクセスを拒否する
  • 全てのログ機能は信頼されたシステム(例:サーバー)で実装する
  • ログ機構はセキュリティイベントの成功/失敗両方をサポートする
  • ログが重要なイベントデータを記録することを保証する
  • 信頼できないデータが含まれるログをビューワーやソフトウェアを利用して参照する場合にコードとして実行されないようにする
  • 許可された個人のみにログへのアクセスを許可する
  • ログ操作に統一したライブラリ関数を利用する
  • 機密扱いのデータをログに保存しない。これには不必要なシステムの詳細情報、セッションIDやパスワードなどが含まれる
  • ログ分析を行う機構があることを保証する
  • 全ての入力バリデーションの失敗をログする
  • 全ての認証要求、特に失敗をログする
  • 全てのアクセス制御の失敗をログする
  • 予期しない状態データの変化を含む、全てのデータ改竄イベントをログする
  • 全ての無効または期限切れのセッションIDでの接続をログする
    (訳注:PHPのセッションモジュールを普通に使っていてはできません。検討します)
  • 全ての例外をログする
  • セキュリティ設定の変更も含み、全ての管理者機能のログする。
  • 全てのTLS接続失敗をログする
  • ログエントリの完全性をバリデーションする為、暗号理論的ハッシュ関数を利用する

データ保護

  • 最小権限の原則、ユーザーにはタスクを実行するために必要な機能、データおよびシステムのみへのアクセスに制限、を実装する
  • サーバーに保存された全ての機密データのキャッシュや一時的コピーを許可されていないアクセスから保護し、一時的なコピーは必要とされなくなった時点で廃棄する
  • 認証関連データなど非常に気密性の高いデータはサーバー側であっても暗号化する。常によく検証されたアルゴリズムを利用する。”暗号の取り扱い”を追加のガイドとして参照
  • サーバー側のソースコードがユーザーからダウンロードされないよう防ぐ
  • パスワード、接続文字列やその他の気密性のある情報をクリアテキストで保存したり、暗号理論的に安全でない方法でクライアント側に保存しない。これらには安全ではないMSビューステート、Adobe Flashやコンパイルされたコードなども含まれる
  • ユーザーがアクセス可能なコードからコメントを削除する。これらのコメントはバックエンドの機密情報が含む場合もある
  • 不必要なアプリケーションやシステムドキュメントを削除する。これらは攻撃者に有用な情報を与えることがある
  • HTTP GETリクエストのパラメータに機密情報を含めない
  • 機密情報を含むページ、認証ページ含む、では自動入力機能を無効にする
  • 機密情報を含むページではクライアント側のキャッシュを無効にする。より効果が低いCache-Control: no-storeをHTTP/1.0互換性の為に、Pragma: no-cacheを一緒に利用する
  • アプリケーションはデータが必要に無くなった場合に備え、機密データを削除できなければならない
  • サーバーに保存された機密データに対する適切なアクセス制御を実装する。これらには特定のシステムユーザーによってのみアクセスできるキャッシュデータ、一時ファイルのデータを含む

通信セキュリティ

  • 機密データの送信には暗号を実装する。HTTP通信では機密ファイルは暗号は暗号化し、TLS通信の場合でも追加の暗号として用いる
  • TLS証明書は正当でなければならず、正しいドメインであり、有効期限内で中間証明書が必要な場合は一緒にインストールされていなければならない
  • TLS接続に失敗した接続は安全でない接続にフォールバックしてはならない
  • 認証が必要なアクセスとその他機密情報を扱うコンテンツ全てにTLS接続を利用する
  • 機密情報を含む外部システムの接続にTLS接続を利用する
  • 適切に設定された単一の標準TLS実装を利用する
  • 全ての接続で文字エンコーディングを指定する
  • 外部システムにアクセスする場合、HTTP REFERERから機密情報を含むパラメータをフィルターする

システム設定

  • サーバー、フレームワークおよびシステムコンポーネントが最新バージョンであることを保証する
  • サーバー、フレームワークおよびシステムコンポーネントがバージョンに対応した全てのパッチが適用されていることを保証する
  • ディレクトリリスティングを無効化する
  • Webサーバー、プロセスとサービスアカウントの権限を可能な限り最小限にする
  • 例外が発生した場合、安全に終了する
  • 全ての不必要な機能とファイルを削除する
  • テストコードや運用時に必要ない機能はデプロイ前に全て削除する
  • サーチエンジンなどでのインデックスを防ぐためのrobots.txtファイルによってディレクトリ構造が漏れないようにする。公開しないディレクトリは1つのディレクトリにまとめ、個々のディレクトリ設定とせず、1つのディレクトリを指定するだけで良いディレクトリ構成にする。
  • アプリケーションがGETまたはPOSTのどちらをサポートするのか定義し、異るページでは異る処理が行われることを明確にする。
  • WebDAV拡張など不必要なHTTPメソッドは無効にする。もしファイル処理にHTTP拡張メソッドが必要な場合、良く検証された認証機構を利用する
  • WebサーバーがHTTP 1.0と1.1の両方をサポートする場合、両方が同じように設定されていることを保証する。開発者が違いがあることを理解していることを保証する。(例:拡張HTTPメソッドの処理など)
  • HTTPレスポンスヘッダーからOS、Webサーバーバージョン、アプリケーションフレームワークなど、不必要な情報を削除する
  • アプリケーションのセキュリティ設定関連の情報は監査の為に人が読める形式の出力をサポートしなければならない
  • 資産管理システムを実装し、システムコンポーネントとソフトウェアを登録する
  • 開発環境は運用ネトワークから分離し、許可された開発とテストグループにのみアクセスを許可する。開発環境は運用環境より安全でない設定であることが多く、攻撃者は違いを共通する弱点の発見に利用したり、攻撃へ導いたりする
  • ソフトウェアの変更管理システムを導入し、開発環境/運用環境両方の変更を記録/管理する
    (訳注:gitなどのバージョン管理システムを導入する。DBを用いた構成管理を行う)

データベースセキュリティ

  • 強い型付けのプリペアードクエリを利用する
    (訳注:SQLiteのデータ型は特殊なので、SQLiteでは特に重要。ただし、データベースのデータ型で表現可能な範囲を制限するようなデータ型の強制、例えば64ビット整数のカラムに32ビット整数を強制すると別の問題が発生する。不用意な強い型付けはNG)
  • 入力バリデーションと出力エンコーディングを利用する。メタ文字(意味を持つ文字)に対応していることを保証する。もしこれらが失敗した場合、データベースコマンドを実行してはならない
    (訳注:メタ文字はSQL文とは限らない。現在のDBはJSON、XML、正規表現など様々なシステムをサポートし、それぞれに意味がある文字がある)
  • 変数が強い型付けであることを保証する
    (訳注:無条件に強い型付けにすれば良いものではありません
  • データベースにアクセスする場合、アプリケーションは最も低い権限でアクセスする
    (訳注:理想的には検索しか行わない場合、読み込み権限のみを持つ接続でアクセスする方が良い。現実にはアクセスが多いサイトの場合、データベース接続数が2倍以上になるので難しい場合が多いが、リードオンリーのレプリカにアクセスする、などの対策は取れる)
  • データベースアクセスには安全なクレデンシャルを利用する
  • 接続文字列はアプリケーション内にハードコードしない。接続文字列は信頼できるシステム上の別の設定ファイルに保存し、これらは暗号化する
  • データアクセスはストアードプロシージャーを利用して抽象化し、データベースのベーステーブルのアクセス権限の削除を許可する
    (訳注:直訳で解りずらいですが、ストアドプロシージャーのみに権限を与え、テーブルにアクセス権限を与えない、ということです)
  • 接続が不必要になったら即座に切断する
    (訳注:永続的接続を使うな、ということではありません)
  • 全てのデフォルトのデータベース管理者パスワードを変更するか削除する。強いパスワード/パスフレーズを利用するか、多要素認証を実装する
  • 不必要なデータベース機能を無効にする(例:不必要なストアードプロシージャーやサービス、ユーティリティパッケージ、最低限必要な機能とオプションをインストールする(攻撃可能範囲の削減))
  • 不必要なデフォルトのベンダーコンポーネントを削除する(例:サンプルスキーマ)
  • 全てのデフォルトアカウントを無効にする。例外はビジネス要求に必要な場合
  • アプリケーションはそれぞれの信頼区分に応じて異るクレデンシャルでデータベースにアクセスする(例:ユーザー、リードオンリー ユーザー、ゲスト、管理者)

ファイル管理

  • あらゆる動的インクルード関数に対してユーザーが送信したデータを直接渡さない
    (訳注:全てのファイルを開く関数でユーザーが送信したデータを渡さない)
  • ファイルアップロードの前に認証を要求する
  • ビジネスの目的の必要なファイルタイプのみアップロードできる可能なファイルを制限する
  • ファイルヘッダーをチェックしてアップロードされたファイルタイプが期待する物であるかバリデーションする。拡張子のチェックだけでは不十分
  • アプリケーションと同じWebコンテクストにファイルを保存しない。ファイルはコンテンツサーバーかデータベースのどちらかに保存する
  • Webサーバーによって実行される可能性のあるファイルのアップロードを禁止または制限する
  • アップロードディレクトリのファイルの実行権限は削除する
  • UNIX環境では目的のファイルディレクトリをアソシエイテッドパスを使った論理ドライブとしてマウントするかchroot環境を利用し、安全なアップロードを可能にする
  • 存在するファイルを参照する場合、許可するファイル名と拡張子のホワイトリストを利用する。渡されるパラメータはバリデーションし、期待する値と異る場合は拒否するか、その値を使わずにハードコードされたデフォルト値を利用する
  • ユーザーから渡されたデータを動的リダイレクトに利用しない。もしこれを許可しなければならない場合、バリデーションされた物のみか相対URLパスのみ受け入れる
  • ディレクトリやファイルパスを渡さない。定義済みのパスリストのインデックス値を利用する
  • 決して絶対パスをクライアントに送らない
  • アプリケーションファイルとリソースが読み込み専用であることを保証する
    (訳注:最近のアプリは自動更新やアプリからのインストールをサポートしているので困難になりつつあるが、これらのシステムでも不可能ではない)
  • ユーザーがアップロードしたファイルにウィルス/マルウェアが含まれないかスキャンする

メモリ管理

  • 信用できないデータには入力と出力制御を行う
  • バッファサイズが指定されたサイズと同じか確実にチェックする
  • コピーするバイト数を指定できる関数、strncpy()など、を利用する場合、コピー先バッファサイズがコピー元バッファサイズと同じであるよう注意する。ヌル文字で終端されている文字列とは限らない
  • 関数がループで呼ばれている場合、既に割り当て済みメモリへの書き込みが安全であることを確認し、バッファのバウンダリをチェックする
  • 全ての入力文字列はコピーや連結する前に、合理的な長さに切り詰める
  • 明示的にリソースをクローズし、ガーベッジコレクションに頼らない(例:接続オブジェクト、ファイルハンドル、など)
  • 利用可能な場合、コード実行不可なスタックを使う
  • 脆弱な関数として知られている関数は避ける(例:printf、strcat、strcpyなど)
  • 関数が完了する際に全ての終了箇所で割り当て済みのメモリを適切に解放する

一般的コーディングガイド

  • 一般的タスクには管理されていない新しいコードを作るより、テスト/保証されたコードを利用する
  • OSのタスクを実行する場合、特定のタスクに設計されたAPIを利用する。アプリケーションからOSに、特にアプリケーションからシェルを使ったコマンドは、直接実行させない
  • インタープリタコード、ライブラリ、実行ファイルと設定ファイルにはチェックサムやハッシュを用いて完全性のチェックを行う
    (訳注:この種の処理にはHMACを利用すると良い)
  • 同時の複数リクエストを防止するためロックを利用するかレースコンディションを防止するための同期メカニズムを利用する
  • 共有変数やリソースは不適切な同時アクセスから保護する
  • 全ての変数やデータ保存場所は、宣言するか最初の利用の直前に、明示的に初期化する
  • アプリケーションが昇格した権限で動作しなければならない場合、権限の昇格はできる限り遅くし、権限の降格はできる限り早くする
  • プログラミング言語がサポートするデータ型とどのように数値計算が行われるがを理解し、計算エラーを回避する。バイトサイズの不一致、プレシジョン(精度)、符号付き/符号無しの違い、丸め、型変換とキャスト、数値以外(NaN)計算、データ型に対して大きすぎる/小さすぎる場合に言語がどのように処理するかに大きな注意を払う
    (訳注:これはデータ型が弱いスクリプト系言語であっても、正しくコードが実行されることを保証するために重要な要素です)
  • ユーザー入力をいかなる動的実行関数にも与えない
  • ユーザーが新しいコードや既存のコードを変更することを制限する
  • 全ての契約によって作られたアプリケーション、サードパーティコードとライブラリはビジネス要求を満たすか、機能が安全か検証するかレビューする。これらは新しい脆弱性導入の原因となる
  • 安全な更新を実装する。アプリケーションが自動更新を利用する場合、暗号理論的な署名をコードに利用し、ダウンロードしたクライアントが署名を確認することを保証する。コードを保存するサーバーからの転送には暗号通信を利用する

付録A

External References:

訳注:最後のSQLとXSSチートシートのURLは古いのでOWASPのSQLXSSチートシートを参照

Security Advisory Sites:

Useful resources to check for known vulnerabilities against supporting infrastructure and frameworks

付録B – 用語集

不正利用ケース: 意図的、意図的でないソフトウェアの誤った使い方の説明。不正利用ケースはソフトウェア設計の検証に利用する。

アクセス制御: ユーザーや他のエンティティへの許可/拒否、システムリソースへのアクセスを制御する機構。一般に階層構造を持つロールやロールの中の個々の権限に基づいており、システムからシステムへのアクセスも含まれる

認証(Authentication): ソフトウェアを利用するユーザーやその他のエンティティを識別し検証する制御機構。

可用性(Availability): システムのアクセス性と有用性の評価。

正規化(Canonicalize): 様々なエンコーディングや表記方法のデータを1つの単純な形式に統一すること。

通信セキュリティ(Communication Security): ソフトウェアが情報を安全な方法で送信/受信することを確実にすることを助ける制御一式。

機密性(Confidentiality): 認証された物(ユーザーやプロセス)にのみ情報が参照されることを保証すること。

コンテクスト出力エンコーディング(Contextual Output Encoding): 出力データがアプリケーションによってどのように利用されるかに従ってエンコーディングすること。個別の方法は出力データの利用方法によって異る。 もしデータがWebクライアントへのレスポンスとして出力される場合、HTML文書のボディ、HTML属性、JavaScriptコード内、CSS内、URLなど、これらの出力を想定する。SQLクエリ、XML、LDAPなどを利用する場合も考慮しなければならない。

クロスサイトリクエストフォージェリ(CSRF – Cross Site Request Forgery): 外部のWebサイトやアプリケーションがアクティブなセッションを持つクライアント(訳注:ログイン状態のクライアントなど)に意図しないリクエストを他のアプリケーションに強制させること。アプリケーションが利用されていることを知られているか利用していること予測できる場合に、ブラウザが自動的にURLとパラメーターなど必要なセッション情報を脆弱なアプリケーションに全て送信するとアプリケーションは脆弱になる。(この脆弱性はこの文書で個別に取り上げた唯一の攻撃方法です。それは関連する脆弱性がとても一般的なうえ正しく理解されていないからです)

暗号の利用(Cryptographic Practices): 暗号処理がアプリケーション内で安全に利用されていることを保証する一連の制御。

データの保護(Data Protection): ソフトウェアが情報を安全な方法で保存することを保証する一連の制御。

セキュリティ(Security): ソフトウェアがデータベースを安全に利用し、データベースが安全に設定されていることを保証する一連の制御。 (訳注:原文は ”A set of controls that ensure that software interacts with a database in a secure manner and that the database is configured securely.” この用語の定義には異論が多いと思われます)

エラー処理とログ(Error Handling and Logging): アプリケーションがエラーを安全に処理し、イベントログを適切に行うこと保証する制御。

(脆弱性の)攻撃(Exploit): 脆弱性を利用し攻撃すること。一般に脆弱性を利用してソフトウェアセキュリティ制御を破壊すること目的とした故意の操作。

ファイル管理(File Management): プログラムと他のシステム上のファイル操作を行う一連の制御。

一般的コーディングプラクティス(General Coding Practices):  他の分類を簡単に適用できないコーディングプラクティス。

危険な文字(Hazardous Character): 意図された文字の利用範囲を越え、アプリケーションの意図した操作に影響を与えたり、システムによって特別な意味を持つと解釈される可能性のあるあらゆる文字やエンコードされた文字表現。これらの文字は以下の目的に利用される可能性がある。

  • 既存のコードや制御文の構造の改ざん
  • 新たな意図しない新しいコードの挿入
  • パスの変更(訳注:ファイルパスやURLのパスなど)
  • プログラムの関数やコードが予期しない結果の生成
  • エラー状態の生成
  • アプリケーションやシステムを好ましくない状態にする上記全て効果を持つ

HTMLエンティティエンコード(HTML Entity Encode): 特定のASCII文字をHTMLエンティティの同等文字に置き換えるプロセス。例えば、HTMLエンコードは”<“文字をHTMLエンティティで同等な”&lt;”に置き換える。HTMLエンティティはほとんどのインタープリター、特にWebブラウザに於て、特定のクライアント側の攻撃を”不活性化”させる。(訳注:HTMLエンティティエンコードはJavaScriptインジェクション対策に利用できる)

影響(Impact):  望まないイベントの発生により生まれる、ビジネス上で好ましからざる影響。脆弱性が悪用されることによりこの結果が生まれる。

入力バリデーション(Input Validation): 全ての入力が期待するデータ型、長さ、範囲、許可した文字セットであり、危険な文字と知られている文字などを含めない、などの属性がアプリケーションが期待する物であることを確認する一連の制御。

Integrity: The assurance that information is accurate, complete and valid, and has not been altered by an unauthorized action.

完全性(Integrity):情報が正確、完全かつ妥当であり不正な操作によって改ざんされていないことの保証。

イベントデータログ(Log Event Data): これには次の物を含めなければならない

  1. 信頼できるシステムからのタイムスタンプ
  2. それぞれのイベントの重大性の評価
  3. 他のログと一緒に記録されている場合、セキュリティ関連イベントであることのタグ(以下、未訳)
  4. Identity of the account/user that caused the event
  5. Source IP address associated with the request
  6. Event outcome (success or failure)
  7. Description of the event

Memory Management: A set of controls that address memory and buffer usage.

Mitigate: Steps taken to reduce the severity of a vulnerability. These can include removing a vulnerability, making a vulnerability more difficult to exploit, or reducing the negative impact of a successful exploitation.

Multi-Factor Authentication: An authentication process that requires the user to produce multiple distinct types of credentials. Typically this is based on something they have (e.g., smartcard), something they know (e.g., a pin), or something they are (e.g., data from a biometric reader).

Output Encoding: A set of controls addressing the use of encoding to ensure data output by the application is safe.

Parameterized Queries (prepared statements): Keeps the query and data separate through the use of placeholders. The query structure is defined with place holders, the SQL statement is sent to the database and prepared, and then the prepared statement is combined with the parameter values. The prevents the query from being altered, because the parameter values are combined with the compiled statement, not a SQL string.

Sanitize Data: The process of making potentially harmful data safe through the use of data removal, replacement, encoding or escaping of the characters.

Security Controls: An action that mitigates a potential vulnerability and helps ensure that the software behaves only in the expected manner.

Security Requirements: A set of design and functional requirements that help ensure the software is built and deployed in a secure manner.

Sequential Authentication: When authentication data is requested on successive pages rather than being requested all at once on a single page.

Session Management: A set of controls that help ensure web applications handle HTTP sessions in a secure manner.

State Data: When data or parameters are used, by the application or server, to emulate a persistent connection or track a client’s status across a multi-request process or transaction.

System: A generic term covering the operating systems, web server, application frameworks and related infrastructure.

System Configuration: A set of controls that help ensure the infrastructure components supporting the software are deployed securely.

Threat Agent: Any entity which may have a negative impact on the system. This may be a malicious user who wants to compromise the system’s security controls; however, it could also be an accidental misuse of the system or a more physical threat like fire or flood.

Trust Boundaries: Typically a trust boundary constitutes the components of the system under your direct control. All connections and data from systems outside of your direct control, including all clients and systems managed by other parties, should be consider untrusted and be validated at the boundary, before allowing further system interaction.

Vulnerability: A weakness that makes the system susceptible to attack or damage.

yohgaki:
Related Post
Leave a Comment