安全なwebアプリケーションの作り方を読んだ

こんにちは。秋ですね。
昨日暖かかったし、今日は半袖で行けるやろって外出して後悔しています。
アラサー男とは思えない軽はずみな判断に我ながら絶句しています。
それでも今日も僕は元気です。

そんなどうでもいいことはともかくとして、
今回は「安全なWebアプリケーションの作り方」を取り上げます。
この本を読もうと思った背景ですが、ズバリ上司からの指摘です。
基本情報は取ったから知識としてはあっても、
それが実際の開発においてどう対策されているかといったことが分かっていない、と。
おっしゃる通り。
そこでよさげな本を調べた結果、この本に行き着いたわけです。

というわけで、この本の全体の構成から入ります。

全体の構成

  • 第1章 脆弱性とはそもそも何か
  • 第2章 実習環境のセットアップ
  • 第3章 HTTP、クッキー、セッション
  • 第4章 Webアプリケーションの機能毎の脆弱性
  • 第5章 代表的なセキュリティ機能
  • 第6章 文字コードとセキュリティ
  • 第7章 携帯電話特有の脆弱性
  • 第8章 Webアプリケーション以外の側面からの安全性向上施策
  • 第9章 開発プロセス

第1章 Webアプリケーションの脆弱性とは

脆弱性とは、悪用できるバグのこと。 セキュリティバグとも言う。

  • 悪用の例
    • 個人情報などの秘密情報を勝手に閲覧する
    • Webサイトの内容を書き換える
    • サイトを閲覧した利用者のPCをウイルスに感染させる

経済的損失、法的な問題への発展、利用者への回復不能なダメージ、
ボットネットワークへの構築なんかにつながるからダメ!!

  • ボットネットワークとは? ボットとは、PCに感染後、外部からの指令を受けて不正活動を行うマルウェアの事。 ボットネットワークとは、脆弱性のある改ざんされたWebサイトを閲覧した利用者のPCが ボットに感染して、そうしたPC同士がネットーワーク化した状態のこと。 攻撃者はボットネットワークを使ってDDos攻撃や迷惑メール送信を行う。

脆弱性には2種類ある。

  1. バグによるもの
  2. セキュリティ意識の不足からチェック機能が不足しているもの

脆弱性はバグだけではなくHTTPSを使っていないなど、セキュリティ機能の不足も含まれる。

第2章 環境設定

mac * vagrant なので、このサイトを参考に環境構築。

第3章 Webセキュリティの基礎

HTTPやセッション管理についての知識がなければ脆弱性を作り込む原因になるためHTTPを学ぶ必要がある。

GETとPOSTの使い分け

  • GET
    • 参照(リソースの取得にのみ用いる)
    • データ更新など副作用を伴うリクエストには用いない
  • POST
    • 送信データが多い場合
    • 秘密情報を送信する場合
    • データ更新など副作用を伴う場合

セッションとクッキー

  • クッキーセット、クッキーを含めたリクエストの流れ
    • ブラウザがサイトに対するクッキーを保持していない場合、レスポンスヘッダでクッキーをセットさせる。
      • (ex) Set-Cookie:PHPSESSID=074vspp57rr1j1dsk6gc6gqkm5; path=/
    • 次回アクセス時には、リクエストヘッダでクッキーを送信する。
      • (ex) Cookie:PHPSESSID=074vspp57rr1j1dsk6gc6gqkm5
    • サイトはクッキーに基づいてユーザーを判別できる。
  • アプリケーションデータの保持のためにクッキーは通常利用しない
    • クッキーが保持できる値の個数や文字列長には制限があるから
    • クッキーの値は利用者本人には参照・変更できるので、秘密情報の格納に向かないから
    • クッキーには整理番号としてのセッションIDを格納しておき、実際の値はサーバー側で管理する。
  • クッキーの属性
    • Domain
      • ブラウザがクッキー値を送信するサーバーのドメイン
        • この属性を指定した場合、後方一致で複数ドメインに送られうる。
          • (ex) example.jp を指定 => example.jp, a.example.jp, a.b.example.jp などに送信される。
        • クッキーのドメイン属性は原則として指定しない
    • Path
    • Expires
      • クッキー値の有効期限。設定しない場合はブラウザの終了まで
    • Secure
      • SSLの場合のみクッキーを送信
    • HttpOnly

受動的攻撃と同一生成元ポリシー

  • Webアプリケーションに対する攻撃は2種類ある
    1. 能動的攻撃
    2. 攻撃者がWebサーバーに直接攻撃すること
    3. 受動的攻撃
    4. Webサイトの利用者に罠を仕掛けることで、罠を閲覧したユーザを通してアプリケーションを攻撃すること。
      • 罠サイトへの誘導、正規サイトに罠を仕掛けるなど。
  • 同一生成元ポリシー
  • JS以外のクロスドメインアクセス
    • img, script, CSS, formのaction属性はクロスドメインの指定ができる。
    • JSONPを用いると、JSで同一生成元でないサーバーのデータにアクセスできるが、 情報漏洩の危険があるためJSONPでは公開情報のみ提供するべき。

Webアプリケーションの機能別に見るセキュリティバグ

脆弱性の分類

  • 脆弱性は大きく分けて2種類
    • 出力に起因する脆弱性(=インジェクション系脆弱性)
      • HTML、HTTP、SQLなど、Webアプリケーションに関わる技術がテキスト形式のインターフェースであることを利用。
        • カンマやタブ、シングルクオートなど、決められた文法を持っていることを利用して攻撃する。
    • 処理に起因する脆弱性

入力処理とセキュリティ

  • 入力値検証はアプリケーションの仕様に基づいて行う
  • 文字エンコーディングの検証
  • 制御文字を含む文字種の検証
    • バイナリセーフな関数かどうかの確認も必要
      • バイナリセーフ - Unixなどで文字列の終端を示す'\0'を示すを正しく扱えるかどうか
  • 各パラメータの文字種や文字数の検証

クロスサイトスクリプティング(XSS)

  • 外部からの入力に応じて表示内容が変化する箇所のHTML生成の実装の問題から生じる脆弱性
    • (ex)フォームに入力した内容をそのまま次のページで確認するとする。 入力内容が「<script>alert(document.cookie)</script>」出会った場合、 クッキーが表示される。
    • 上の例のように、サイト内容の書き換えやJSの実行などができる。
  • 3種類の被害
    1. クッキー値の盗難
    2. JSによる攻撃
    3. 画面の書き換え
  • 対策
    • HTMLの文法上特別な意味を持つ特殊記号(メタ文字)をエスケープすること。
      • 「<」、「>」、「&」、「"」、「'」 これらの記号が入力されてHTML上に出力される場合には 「<(HTML上では < )」、「>(HTML上では > )」などに変換して出力する
    • HTTPレスポンスに文字エンコーディングを明示する。
    • 入力値の検証
    • クッキーにHttpOnly属性を付与する
    • TRACEメソッドを無効化する

SQLインジェクション

データベースと連動したWebサイトで、データベースへの問い合わせや操作を行うプログラムにパラメータとしてSQL文の断片を与えることにより、 データベースを改ざんしたり不正に情報を入手する攻撃。また、そのような攻撃を許してしまうプログラムの脆弱性のこと。

  • SQLインジェクションによる認証回避
    • 下のように入力フォームの ID と パスワード を変数で直接SQLに入れているとき。
SELECT * FROM users WHERE id = "$user" AND password = "$id";

$user = 'yoshinaga', $password = ' " OR "a" = "a' とすると、下記のようなSQL文になる。

SELECT * FROM users WHERE id = "yoshinaga" AND password = " " OR "a" = "a";

id が存在する場合、ログインできてしまう。 同様の形で、データの消去、改ざん、挿入などが行うことができる。

my $sql = 'SELECT id, name, weight, muscle FROM users WHERE muscle = ?';
my $sth = $dbh->prepare($sql);
     $sth->bind_params(1, '; DELETE FROM users;');
     $sth->execute();
  • 上の例の場合、プレースホルダを用いていなければusersテーブルのデータが全て消去されてしまうが、 プレースホルダを用いることによって、? 箇所に入る文字列が必要に応じてエスケープされるため、データ消去は起こらない。

クロスサイト・リクエストフォージェリ(CSRF)

決済、送金、ユーザー情報の変更など、ログインした利用者のアカウントにより行われる取り消しできない操作の脆弱性

  • 攻撃手順例
    1. サイトAにログインしているユーザーが罠サイトを閲覧。
    2. 罠サイトからサイトAにPOSTリクエス
    3. 送信先ドメインは正しく、HTTPリクエストなのでクッキーは送信される。
    4. POSTリクエストに基づいた処理が行われる
  • 対策が必要な箇所
    • 購入や変更などの実際に処理が行われる箇所
    • 確認画面ではないので注意
  • 対策方法
    • トークン(秘密情報)の埋め込み
      • 確認画面でトークンを発行しておき、実際の処理の際にそのトークンの照合を行う
    • パスワードの再確認
    • HTTPリクエストヘッダーのRefererチェック
      • Refererを送らない設定にしているユーザーもいて、その場合認証ができない
  • その他の保険的対策
    • 処理があったことをメール送信することで不正に早く気づける

セッションハイジャック

Webアプリケーションでは認証結果などの現在の状態を記録するのにセッション管理機構が使われている。 現在主流のセッション管理機構は、クッキーなどにセッションIDという識別子を記憶させて、 セッションIDをキーとしてサーバー側で情報を記憶する方法。 ある利用者のセッションIDが第三者に知られると、その利用者になりすましてアクセスできる。

  • 三者がセッションIDを知る手段
    • セッションIDの推測
      • 独自でセッションIDを生成した場合には推測される可能性がある。
    • セッションIDの盗み出し
      • セッションIDをURL埋め込みしていたために、リンク先に飛んだ時にRefererで流出する
      • クッキー属性の不備
      • ネットワーク的にセッションIDが盗聴される
      • XSSなどアプリケーションが原因となって流出する
    • セッションIDの強制
      • セッションIDの固定化攻撃
        • 利用者にセッションIDをセットしておく
  • 対策
    • クッキー管理機構は自作せず、Webアプリケーション開発ツールのものを使う
    • クッキーにセッションIDを保存する(URLではなく)
    • 認証成功時にセッションIDを変更する(固定攻撃対策)
    • 認証前にセッション変数に秘密情報を保存しない

リダイレクト処理関連の脆弱性

  • オープンリダイレクト脆弱性
    • リダイレクト先のURLを外部から指定でき、リダイレクト先のドメインチェックが不十分な場合、 別サイトにリダイレクトさせられてしまう脆弱性 知らないうちに同じデザインの別ドメインのログイン画面に遷移させられているなど
    • オープンリダイレクトが問題ない場合
      • もともと外部ドメインに遷移する仕様である
      • 利用者にとって外部ドメインに遷移することが明白である
        • 広告とか
  • HTTPヘッダインジェクション
    • リダイレクトやクッキー発行など、外部からのパラメータを元にHTTPレスポンスヘッダを出力する際の脆弱性
    • 任意のクッキー生成、任意のURLへのリダイレクト、レスポンスボディの改変、XSS同様の被害がありうる
  • 2つの脆弱性への対策
    • リダイレクト処理には極力専用のライブラリ関数を用いる
    • リダイレクト先のURLを固定にする
    • リダイレクト先のURLを直接指定せず、番号指定などにする
    • リダイレクト先のURLのドメインを十分にチェックする

クッキー出力にまつわる脆弱性

  • 基本的にはクッキーにはセッションIDのみを用いる
    • クッキーは改変されうるため
  • クッキーの流出を避けるため、https通信の場合クッキーにセキュア属性をつける

メール送信の問題

  • メール送信には専用のAPIやライブラリを使用する
    • sendmailコマンドによるメール送信は、OSコマンド・インジェクション、 メールヘッダ・インジェクションといった脆弱性に繋がる

ファイルアクセスに関わる問題

OSコマンド呼び出しの際に発生する脆弱性

  • シェル呼び出し機能を呼び出す関数(system関数)に外部からのパラメータを渡した場合に発生する
    • 「;cat /etc/passwd」といったような変数が渡されると情報漏洩する
  • 原則としてOSコマンドを使わない実装方法を使うこと
  • シェル呼び出し機能のある関数を避ける
    • 使う場合には外部から入力された文字列を渡さない、渡す場合はエスケープする等の処理を行う

ファイルアップロードに関わる問題

不正を働くスクリプトがアップロードされ、 そのスクリプトが公開サーバにあって直接アクセスできる場合には、 不正なスクリプトの実行によって情報が流出する恐れがある

  • 対策
    • 拡張子をチェックすること
    • コンテンツ内容をチェックすること
      • 画像として読み込めるかなど
    • 公開サーバに置かず、スクリプトでアクセスするようにすること

長かったのでまとめ

  • ライブラリが用意されている場合には独自実装せずに素直にライブラリを使うこと
  • 外部から入力されるパラメータを処理すること
    • SQLならプレイスメントホルダを用いる
    • 入力データが画面表示される場合にはエスケープすること
  • 重要な処理がされる前にはサイド認証すること
  • クッキーにはパスワードなど重要情報をセットしないこと
  • クッキーのセキュア属性、ドメイン属性、HttpOnly属性など正しく設定すること
  • ログイン操作がある場合には、ログイン時にセッションIDを変えるとよい

代表的なセキュリティ機能

認証機能

  • ログイン機能のセキュリティに必要なこと
    • 前章までのSQLインジェクションXSS、セッションID固定化などの対策
    • パスワードの文字種、桁数の要件を検討する
    • ログインIDを公開しないこと
    • 積極的なパスワードポリシーのチェック
      • ユーザーIDと同じパスワードは弾くなど(ジョーアカウントと呼ばれる)
    • 総当たり攻撃対策のため、パスワードの保存方法を工夫すること
      • ハッシュ関数にかけたパスワードの保存
      • ソルト
        • ハッシュ関数にかける元データに追加する文字列のこと、ユーザーIDを暗号化した文字列など
      • ストレッチング
        • ハッシュ計算を繰り返し行うこと
  • 自動ログインに関して
    • ログイン状態の保持は3つの実装方法がある
      • セッションの寿命を伸ばすこと
      • トークンを使うこと(一番好ましい)
        • トークンをクッキーにセットして、そのトークンとユーザーIDと有効期限をDBで管理する
        • ログアウト時には、ユーザーIDを自動ログインテーブルから削除することで複数端末も対応できる
      • チケットを使うこと
        • 認証チケットとは認証情報をサーバーの外に持ち出せるようにしたもの
    • トークン方式のメリット
      • 自動ログインを選択しない利用者に影響を与えない
      • 複数端末からログインしている場合でも一斉にログアウトできる
      • 管理者が特定利用者のログイン状態をキャンセルできる
      • クライアント側に秘密情報が渡らない
  • エラーメッセージを詳細にしない
    • IDが間違っています等、だと使用されているIDが判明してしまう

アカウント管理

  • ユーザーが入力したメールアドレスは必ず受信確認を行う
  • 重要な処理に際しては再認証
  • 重要な処理のメール通知
  • アカウント管理では以下の脆弱性が発生しやすい

認可

  • 認可とは認証された利用者に対して権限を与えること
  • 認可不備が発生するケース
    • URLやhiddenパラメータ、クッキーなどに権限情報を格納して、それが書き換えられる
    • ディレクトリやファイル名の直打ちでアクセスできる
  • 対策
    • データベースでロール毎に管理するのが望ましい
      • ユーザー1は、管理者権限。 ユーザーには一般ユーザー権限といった形で登録しておき、
        それぞれの権限毎に実行できる処理、表示する情報を変えて、情報の表示・処理実行前に権限を確認する

### ログ

  • ログの必要性
    • 攻撃や事故の予兆をログから把握し、早期に対策する
    • 攻撃や事故の予後調査のため
    • アプリケーションの運用監査のため
  • ログの種類
  • 記録すべきログ
    • ログイン・ログアウト(失敗も含む)
    • アカウントロック
    • ユーザ登録・削除
    • パスワード変更
    • 重要情報の参照
    • 重要な操作
  • ログ出力の実装はログ用のライブラリが言語毎にたいていは用意されている

文字コードとセキュリティ

Webサイトの安全性を高めるために

  • Webサーバーへの攻撃
    • 不要なソフトウェアを稼働させない
    • 脆弱性への対処をタイムリーに行う
    • 一般公開する必要のないポートやサービスはアクセス制限する
      • ポートスキャンでアクセス制限の状態を確認する
    • 認証強度を高める
      • telnetサーバー、FTPサーバーを削除あるいは停止しSSH系サービスのみ稼働させる
      • パスワード認証を停止し、公開鍵認証のみとする
  • 成りすまし
    • DNSキャッシュポイズニング、フィッシングなどで発生する
    • SSL/TLSの導入による対策
  • マルウェア

開発マネジメント

  • 開発ガイドラインの策定
    • 脆弱性毎の対処方法
    • 認証、セッション管理、ログ出力の実装方式
    • 各フェーズでのレビューとテストの方法
  • 開発メンバーの教育による体制の整備
    • 事件事例の紹介
    • 主要な脆弱性の原理と影響
    • 遵守すべき事項
  • 開発プロセスの整備
    • セキュリティ機能の具体化
    • 開発標準の詳細化、テスト方式の決定
    • 画面設計時のセキュリティ機能の確認
      • CSRF対策の必要な画面の洗い出し
      • HTTPSにするページの洗い出し

おわりに

すみません、度を超えた長さになってしまいやした。
こんだけ色々書いといてなんですが、
一番重要なのは、
Webアプリケーションの機能別に見るセキュリティバグ
の章まとめとして書いた部分数行です。
読みながら自分の会社のアプリケーションのコードに出てくるような対策が出てきて、
うちはセキュリティちゃんとやってんだなぁ、と当たり前のことをしみじみ感じました。

それではみなさん、3連休明けの月曜日を張り切って迎えましょう、、、