安全なウェブサイトの作り方を読んだので、理解した内容を自分なりにまとめておきます。資料
上記は3章構成になっていてそれぞれ長めの内容なので、ここでは1章の『ウェブアプリケーションのセキュリティ実装』の設計や実装レベルの解決や対策方法についてまとめます。
上記の内容に沿って、Ruby on Rails での実装方法についても合わせてまとめておこうと思います。
- 根本的解決と保険的解決
- ウェブアプリケーションのセキュリティ実装
- 参考
根本的解決と保険的解決
『安全なウェブサイトの作り方』では、Web アプリケーションにおける脆弱性対策について、以下の分類をしている。
根本的解決
『脆弱性を作り込まない実装』を実現する手法。ここに分類される対策を取ることで、対策対象である脆弱性を狙った攻撃の無効化が期待できる
保険的対策
『攻撃による影響を軽減する』対策手法。脆弱性そのものを無くせないが、下記フェーズでの影響を軽減できる。
フェーズ 具体例 攻撃される可能性の低減 攻撃につながるヒントを与えない 攻撃された場合に脆弱性を突かれる可能性の低減 入力から攻撃に使われるデータをサニタイズする 脆弱性を突かれた場合の被害範囲の最小化 アクセス制御 被害が生じた際の早期周知 事後通知
理想的には根本的解決手法の採用が望ましく、保険的対策のみに頼った設計は推奨されない。保険的対策は、根本的解決の実装漏れがあった場合のセーフティネットとして機能するため、合わせて採用することが有効。
ウェブアプリケーションのセキュリティ実装
SQL インジェクション
概要
データベース(DB)と連携した Web アプリケーションでは、利用者からの入力情報をもとに SQL 文を組み立てる。この時の SQL 文の組み立てに問題がある場合、DB の不正利用を招く可能性がある。こうした攻撃を『SQL インジェクション攻撃』と呼ぶ。
発生しうる脅威
脅威 | 具体例 |
---|---|
DB 内の非公開情報の閲覧 | 個人情報の漏洩 |
DB 内の情報改ざん・消去 | Web ページの改ざん、パスワード変更、システム停止 |
認証回避による不正ログイン | 不正ログインしたアカウントでの操作実行 |
ストアドプロシージャ等を利用した OS コマンド実行 | システム乗っ取り、他への攻撃の踏み台としての悪用 |
根本的解決
-
SQL 文の雛形の中に変数の場所を示す記号(プレースホルダ)をおいて、そこに実際の値を割り当てるもの。 Ruby on Rails の Active Record では次のような実装となる。
# プレースホルダを使用したSQLクエリ
User.where(name: params[:name])
SQL 文の組み立てを文字列結合する場合、エスケープ処理等を行うデータベースエンジンの API を用いて SQL 文のリテラルを正しく構成する
SQL 文の組み立てを文字列結合する場合、SQL 文中で可変となる値をリテラル(定数)で埋め込む。値を文字列型で埋め込む場合はエスケープ処理を実施する。
# sanitize_sql
username = sanitize_sql(username_raw)
query = "SELECT * FROM users WHERE username = #{username}"
results = ActiveRecord::Base.connection.execute(query)
- Web アプリケーションに渡されるパラメータに SQL 文を直接指定しない
保険的対策
エラーメッセージをそのままブラウザに表示しない
エラーメッセージに、データベースの種類やエラー原因、SQL 文等が含まれる場合、SQL インジェクション攻撃につながるヒントになるため表示しない。
データベースアカウントに適切な権限を与える
Web アプリケーションがデータベースに接続する際に使用するアカウントに権限を必要以上に与えない。
OS コマンドインジェクション
概要
Web アプリケーションによっては、外部からの攻撃により Web サーバの OS コマンドを不正に実行されてしまう問題を持つものがある。こうした攻撃のことを『OS コマンドインジェクション攻撃』と呼ぶ。
Ruby での外部コマンドの実行は次のものがあり、サーバ上で利用する場合には注意が必要になる:
system
:コマンドを実行し、実行結果の真偽値を受けとる
result = system("ls -l")
puts result #<= 成功なら true, 失敗なら false
exec
:Ruby のプロセスを外部コマンドに置き換えて実行。コマンド実行結果は受け取らない
exec("ls -l") #<= コマンド実行に成功する場合、Ruby プロセスから抜ける
puts "この行は実行されない"
- バッククォート:外部コマンドを実行し、実行結果を文字列として取得
result = `ls -l`
puts result #<= コマンド実行時の結果
発生しうる脅威
脅威 | 具体例 |
---|---|
サーバ内ファイルの閲覧/改ざん/削除 | 重要情報の漏洩、設定ファイルの改ざん |
不正なシステム操作 | 意図しない OS シャットダウン、ユーザアカウントの追加/削除 |
不正なプログラムのダウンロード | ウィルス/ワーム/ボットへの感染、バックドア設置 |
他システムへの攻撃の踏み台 | サービス不能攻撃、システム攻略のための調査、迷惑メール送信 |
根本的解決
シェルを起動できる言語の利用を避ける
Web アプリケーションに利用されている言語には、シェルを起動できる機能を持つものがある。そうしたメソッドの利用は避け、他の関数で代替する。
Ruby では、上に示した外部コマンドを実行するメソッドは全てシェルを通して実行している。代替手段としては Open3 ライブラリを使え、これはシェルを通さずに外部コマンド実行時の標準入力/出力/エラー出力を操作できる
require 'open3'
Open3.popen3('ls', '-l') do |stdin, stdout, stderr|
while line = stdout.gets
puts line
end
end
保険的対策
シェルを起動できる言語機能を利用する場合は、その引数を構成するすべての変数に対してチェックを行い、あらかじめ許可した処理のみを実行する
シェルを起動できる言語機能の引数を構成する変数に対し、引数に埋め込む前にチェックをかける。チェック方法には、許可リスト方式のホワイトリスト方式を採用する。ブラックリスト方式はチェック漏れが生じる可能性があるため推奨されない。
パス名パラメータの未チェック/ディレクトリ・トラバーサル
概要
Web アプリケーションで、外部からのパラメータに Web サーバ内のファイルを直接指定するものがある。ファイル名指定の実装に問題があると、攻撃者に任意のファイルを指定され、Web アプリケーションが意図しない処理を実施してしまう可能性がある。この攻撃のことを『ディレクトリ・トラバーサル攻撃』という。
発生しうる脅威
脅威 | 具体例 |
---|---|
サーバ内ファイルの閲覧/改ざん/削除 | 重要情報の漏洩、設定ファイル/データファイル/ソースコード等の改ざんや削除 |
個人情報等の重要情報を Web サーバ内にファイル保存しているサイトは注意が必要。サーバ内ファイルを利用する Web アプリケーションの例としては次のようなものがある。
- Web ページのデザインプレートをファイルから読み込む
- 利用者からの入力を指定ファイルに書き込む
根本的解決
外部からのパラメータで Web サーバ内のファイル名を直接指定する実装を避ける
Web サーバ内のファイル名を直接指定する実装では、任意のファイルを指定されることで公開を想定しないファイルが外部から閲覧される可能性がある。
外部からのパラメータで、Web サーバ内のファイル名指定が本当に必要かを見直し、代替方法や設計変更が推奨される。ファイルを開く際は、固定ディレクトリを指定し、ファイル名にディレクトリ名が含まれないようにする
想定しないファイルを開かせないために、アクセスするディレクトリを固定し、
固定ディレクトリ+ファイル名
という形式にする。その際、ファイル名を相対アドレスとした ディレクトリ・トラバーサル攻撃を回避するために、ファイル名
からディレクトリ名を取り除くようにする。
# / と \ を _ に置換
user_input = params[:input].gsub(/[\/\\]/, '_')
そのほかにも、『相対アドレスの絶対アドレス変換+ホワイトリストによる許可』を組み合わせる方法も有効。
user_input_filename = params[:filename]
# アプリケーション内で許可されたディレクトリ
base_directory = "uploads"
relative_path = File.join(base_directory, user_input_filename)
absolute_path = File.expand_path(relative_path)
# 絶対パスが許可されたディレクトリ内にあることを確認
if absolute_path.start_with?(File.expand_path(base_directory))
File.open(absolute_path, 'wb') do |file|
# ファイルを書き込む
end
end
保険的対策
Web サーバ内のファイルへのアクセス権限設定を適切に管理する
アクセス権限が正しく管理できていれば、Web アプリケーションが任意のディレクトリを開く処理を実行しても、Web サーバ側で拒否できる。
ファイル名チェックを行う
ファイル名を指定した入力パラメータ値に
/
,../
等のディレクトリを指定できる文字列を検知したら処理を中止する。URL エンコードした文字列についても考慮すること。
セッション管理の不備
概要
Web アプリケーションにはセッション ID(利用者を識別する情報)を発行し、セッション管理するものがある。セッション ID の発行・管理に不備がある場合、ログイン中のセッション ID を不正取得され、その利用者になりすましてアクセスされる可能性がある。この攻撃のことを『セッション・ハイジャック』と呼ぶ。
また、悪意ある人が用意したセッション ID を何らかの方法で利用者に送り込み、利用者が気づかずにログインすると、そのセッション ID でログインした状態になってしまう。その後、攻撃者は当該のセッション ID でアクセスし利用者になりすます。
用意したセッション ID を送り込めてしまうのは、次のいずれかに該当する場合:
- Web アプリケーションがセッション ID を
POST
メソッドのhidden
パラメータで受け渡す実装 - セッション ID を cookie で受け渡す際に、利用者のブラウザがドメインを跨る cookie 問題を抱えている
- セッション ID を cookie で受け渡す際に、Web アプリケーションサーバに Session Adoption の脆弱性がある
- Web アプリケーションに XSS 等の脆弱性がある場合
発生しうる脅威
脅威 | 具体例 |
---|---|
ログイン後の利用者のみが利用可能なサービスの悪用 | 不正送金、意図しない商品購入/退会処理 |
ログイン後の利用者のみが編集可能な情報の改ざん、新規登録 | 各種設定の不正な変更、掲示板への不適切な書き込み |
ログイン後の利用のみが閲覧可能な情報の閲覧 | 非公開の個人情報の不正閲覧、Web メールの不正閲覧 |
上記のように、ログイン機能を持つ Web サイト全般に注意が必要な問題。具体的には下記のようなサイト:
- 金銭処理が発生するサイト:ネットバンキング、ネット証券、ショッピング、オークション等
- 非公開情報を扱うサイト:転職サイト、コミュティサイト、Web メール等
- その他、ログイン機能を持つサイト:管理者画面、会員専用サイト、日記サイト
根本的解決
セッション ID を推測が困難なものにする
悪意あるものが推測できないようにセッション ID を生成するようにする。セッション管理の仕組みが適用される Web アプリケーションサーバを利用する際は、それが提供する仕組みをすれば良い。
Ruby on Rails ではセッション管理の仕組みがデフォルトで導入されており、自前でセッション ID を生成する必要はない。
セッション ID を URL パラメータに格納しない
セッション ID を URL パラメータに格納していると、ブラウザの Referer 送信機能*1によってセッション ID の含まれた URL をリンク先のサイトに送信してしまう。悪意あるものにそれが渡ると、セッションハイジャックされてしまう。
HTTPS 通信で利用する cookie には secure 属性を加える
HTTPS 通信のみで利用されるように、cookie に
secure
属性を設定する。そうすれば、暗号化された通信を前提とすることになり、盗聴による盗み見を防止できる。ログイン成功後に、新しくセッションを開始する
セッション ID 固定攻撃に対するために、ログインが成功した時点から新しいセッションを開始し、古いセッション ID を無効化する。
ログイン成功後に、既存セッション ID とは別に機密情報を発行し、ページ遷移ごとにその値を確認する
セッション ID とは別に、ログイン成功時に秘密情報を作成して cookie にセットし、cookie の値が一致することを全部のページで確認する。
保険的対策
セッション ID を固定しない
セッション ID は利用者のログインごとに新しく設定し、固定値としない。
セッション ID の cookie の有効期限に注意する
cookie は有効期限を過ぎるまでブラウザに保持される。その時点で保持された cookie が盗まれる可能性があるため、有効期限に気をつける。
クロスサイト・スクリプティング(XSS)
概要
Web アプリケーションには、利用者からの内容や HTTP ヘッダの情報を処理し、Web ページとして出力するものがある。具体的には次のようなもの:
- 入力内容を確認させる表示画面(会員登録、アンケート等)
- 誤入力時に再入力を要求する際に、前の入力を表示するとき
- 検索結果の表示
- エラー表示
- コメントの反映(ブログ、掲示板等)
Web ページの出力に問題がある場合、その Web ページにスクリプト等を埋め込まれてしまう。これを悪用した攻撃を『クロスサイト・スクリプティング攻撃』という。この攻撃は、Web サイトに対してではなく、Web ページを閲覧している利用者 をターゲットしている。
発生しうる脅威
脅威 | 具体例 |
---|---|
本物サイト上に偽のページが表示される | 偽情報の流布による混乱、フィッシング詐欺による重要情報の漏洩 |
ブラウザが保存している cookie の取得 | セッション ID がある場合盗用によるなりすまし、個人情報がある場合その内容の漏洩 |
任意の cookie をブラウザに保存される | セッション ID 攻撃への悪用 |
対策について
XSS への対策は Web アプリケーションの性質に合わせて3つに分類される:
- HTML テキスト入力を許可しない場合の対策(検索機能や個人情報の登録、HTML タグを用いた入力が不要なもの)
- HTML テキスト入力を許可する場合の対策(掲示板やブログ等)
- 全ての Web アプリケーションに共通する対策
HTML テキストの入力を許可しない場合の対策
根本的解決
Web ページに出力する全ての要素に対してエスケープ処理を施す
Web ページの本文や HTML タグの属性値等に相当する全ての出力要素にエスケープ処理する。エスケープ処理は、Web ページの表示に影響する記号文字を置換する(
<
,>
,&
等を<
,>
,&
等)方法がある。Ruby on Rails ではデフォルトでエスケープ処理が行われる:
<!-- use_input: `<script>alert("XSS");</script>` -->
<%= user_input %>
<!-- 出力: `<script>alert("XSS");</script>` -->
URL を出力するときは、『http://』や『https://』で始まる URL のみ許可する
URL には、『http://』や『https://』で始まるもの以外に、『javascript:』ものがある。Web ページに出力するリンク先や画像を、外部からの入力で動的に生成する場合、生成された URL にスクリプトが含まれていると、XSS 攻撃が可能になる場合がある。
例えば、
<a href="リンク先URL"
の形式で Web ページに出力するアプリケーションにおいて、javascript:
等で始まる文字列を入力された場合にスクリプトを埋め込まれる可能性がある。リンク先の URL は、『http://』や『https://』から始まるものを許可する『ホワイトリスト方式』で実装する。
<script>...</script>
要素の内容を動的に生成しないscript
タグ要素を外部入力に依存する形で生成する場合、それらが安全なスクリプトであるかを確実に判断するのは困難なため動的生成は避ける。スタイルシートを任意のサイトから取り込めるようにしない
CSS には
expression()
等を利用してスクリプトを記述することができる。外部入力された CSS が安全かどうかを確実に判断するのは困難なため避ける。スタイルを変えさせたい場合、特定の属性のみ指定できるようにする方法がある。
保険的対策
入力値の内容チェックを行う
入力値全てが Web アプリケーションの仕様に合うものかどうかを確認する処理を実装し、満たさない場合は以降の処理を実施せず再入力を求めるという対策もある。ただし、全ての入力を漏れなくチェックするのは難しい。
HTML テキスト入力を許可する場合の対策
根本的対策
入力された HTML テキストから構文解析木を作成し、スクリプトを含まない必要な要素のみを抽出する
入力された HTML テキストに対して構文解析を行い、『ホワイトリスト方式』で許可する要素のみを抽出する。
Ruby on Rails では以下の方法がある。
ActiveView の sanitize メソッドの利用
ビューに渡す前に使用する。比較的安全な設定で HTML をフィルタリングでき、不要な HTML 要素や属性は削除され、安全なもののみが残る。カスタマイズの柔軟性はあまりない。
user_input = "<p>This is a <a href='http://example.com'>link</a>.</p>" sanitized_html = sanitize(user_input)
sanitize gem の使用
HTML を安全にフィルタリングできる。コントローラやビュー内で使用し、カスタマイズ(参考)もやりやすいらしい。
require 'sanitize' user_input = "<p>This is a <a href='http://example.com'>link</a>.</p>" sanitized_html = Sanitize.fragment(user_input, Sanitize::Config::RELAXED)
上記は、
Sanitize::Config::RELAXED
を指定して比較的緩やかなフィルタリングを実行している。Sanitize::Config
については Configuration が詳しい。
保険的対策
入力された HTML テキストから、スクリプトに該当する文字列を排除する
入力された HTML テキストに含まれるスクリプトに該当する文字列を抽出し排除する。『ブラックリスト』方式による方法であり、危険な文字列を完全に抽出するのは困難なため推奨されない。
全てのアプリケーションに共通する対策
根本的解決
HTTP レスポンスヘッダの Content-Type フィールドに文字コード(charset)を指定する
HTTP のレスポンスヘッダの Content-Type フィールドに
Content-Type: text/html; charset=UTF-8
のように文字コードをして id けいる。この指定を省略した場合、ブラウザは文字コードを推定して画面表示を処理する。一部のブラウザでは、該当部分に特定文字が含まれていると必ず特定の文字コードとして処理するものがあり、攻撃者はこの挙動を悪用し、その文字コードに特化した悪意ある文字列を埋め込む攻撃をする。
上記を防ぐために、
Content-Type
にcharset
を必ず指定すること。Ruby on Rails では
Content-Type
のcharset
はデフォルトでutf-8
が指定されると思われる(config.encoding, head でヘッダのみのレスポンスを生成する )。
保険的対策
Cookie の漏洩対策として、発行する cookie に
HttpOnly
属性を加えTRACE
メソッドを無効化するHttpOnly
は cookie に設定できる属性で、設定された cookie は HTML テキスト内のスクリプトからのアクセスがされる。これにより、Web サイト内に XSS の脆弱性があっても cookie の盗用が防止できる。ただし、ブラウザによって対応が異なるため注意が必要。XSS の潜在的な脆弱性対策として有効なブラウザ機能を有効にするレスポンスヘッダを返す
ブラウザには、XSS 攻撃のブロックを試みる機能を備えたものがある。ユーザの設定によっては無効になっている場合があるので、サーバから明示的に有効にするレスポンスヘッダと返すことで悪用を避けることができる。
クロスサイト・リクエスト・フォージェリ(CSRF)
概要
サービス提供に際しログイン機能を設けている Web アプリケーションが、あるリクエストがログインユーザの意図したものかを識別する仕組みを持たない場合、外部サイトを経由した悪意あるリクエストを受け入れてしまう可能性がある。
そのような Web サイトにログインしたユーザが、悪意ある罠に嵌ると、利用者が予期しない処理を実行させられてしまう可能性がある。
発生しうる脅威
脅威 | 具体例 |
---|---|
ログイン後の利用者のみが利用可能なサービスの悪用 | 不正送金、意図しない商品購入/退会処理 |
ログイン後の利用者のみが編集可能な情報の改ざん、新規登録 | 各種設定の不正変更、掲示板への不適切な書き込み |
上記の攻撃は、下記の技術を用いてセッション管理を実装している Web サイトが攻撃の影響を受ける可能性がある:
根本的解決
処理を実行するページを
POST
メソッドでアクセスするようにし、その『hidden
パラメータ』に秘密情報が挿入されるよう、前のページを自動生成して、実行ページではその値が正しい場合のみ処理を実行する『入力画面⇨確認画面⇨登録処理』のページ遷移を例とする。確認画面表示時に、合わせて秘密情報を『
hidden
パラメータ』に出力する。秘密情報はセッション管理のセッション ID 等に使われる。この時の ID は推測困難なように暗号論的擬似乱数生成器を用いる。次に確認画面から登録処理のリクエストを受けた際は、リクエスト内容に含まれる『
hidden
パラメータ』の値を比較し、一致しない場合は登録しないようにする。処理を実行する直前のページで再度パスワード入力を求め、実行ページでは再入力されたパスワードが正しい場合のみ処理を実行する
処理の実行前にパスワード認証を行うことで脆弱性を解消する。ただし、本対策は画面設計の仕様変更を伴うため、実装変更のみで変えたい場合は他の根本的解決の手法を採用すること。
Referer が正しいリンク元かを確認し、正しい場合のみ処理を実行する
Referer を確認することで本来の画面遷移を経ているかを確認し、Referer が確認できない場合には処理を実行しないようにする。
ただし、攻撃対象の Web ページ上に罠を設置される可能性もあり、本対策が有効に機能しない場合があることに注意する。他にもブラウザの設定によっては、Referer を送信しないようにでき、そうした利用者の利用ができなくなる。
保険的対策
重要な操作を行なった際に、その旨を登録済みのメールアドレスに送信する
メール通知は事後処理なため、CSRF 攻撃を防ぐことはできないが、利用者が異変に気づくきっかけとなる。
HTTP ヘッダ・インジェクション
概要
Web アプリケーションには、リクエストに対して出力する HTTP レスポンスヘッダのフィールド値を、外部から渡されるパラメータ等を利用して動的に生成するものがある。
例えば、リダイレクションの実装としてパラメータから取得したジャンプ先の URL 情報を Location
ヘッダフィールド値に使用する場合や、掲示板等で入力された名前を Set-Cookie
ヘッダフィールド値に使用する場合などがある。
その際に、HTTP レスポンスヘッダの出力処理に問題がある場合、レスポンス内容に任意のヘッダフィールドやボディを追加したり、複数レスポンスを作り出すような攻撃をされる可能性がある。前者を『HTTP ヘッダ・インジェクション攻撃』、後者を『HTTP レスポンス分割攻撃』と呼ぶ。
『HTTP レスポンス分割攻撃』では、レスポンスボディをリバースプロキシ等にキャッシュさせることでキャッシュ汚染(Web ページの差し替え)を引き起こさせる。
発生しうる脅威
脅威 | 具体例 |
---|---|
XSS 攻撃と同等の脅威 | 任意のレスポンスボディを注入されると、利用者のブラウザ上で偽情報を表示させられたり、任意のスクリプトを埋め込まれる等、XSS と同等の脅威がある。 |
任意の cookie 発行 | Set-Cookie ヘッダを注入された場合、任意の cookie が発行され、利用者のブラウザに保存される |
キャッシュサーバのキャッシュ汚染 | キャッシュ汚染を引き起こさせ、Web ページの改ざんと同じ脅威が生じ、利用者は差し替えられた偽のページを参照し続けることになる。XSS の攻撃と異なりキャッシュ汚染はキャッシュサーバに保持されるため、影響を受ける範囲が広く、永続的となる場合もある。 |
cookie を利用してログインのセッション管理を行っているサイトや、サイト内にリバースプロキシとして、キャッシュサーバを構築しているサイトは、特に注意が必要。
根本的解決
ヘッダ出力を直接行わず、Web アプリケーションの実行環境や言語に用意されているヘッダ出力用 API を使用する
Content-Type
フィールド等の HTTP レスポンスヘッダをプログラムで直接出力するような場合に、フィールド値に式の値をそのまま出力すると、外部から与えられた改行が含まれてしまう。
HTTP ヘッダは開業によって区切られるため、任意のヘッダーフィールとやボディが注入される可能性がある。実行環境に用意された API を用いるのが吉。Ruby on Rails では HTTP レスポンスヘッダーを設定する際には、
response
オブジェクトを介して行う:
class MyController < ApplicationController
def my_action
# 例1. カスタムHTTPヘッダーを設定:
response.headers["Custom-Header"] = "Custom Header Value"
render plain: "Hello, World!"
# 例2. キャッシュコントロールヘッダーを設定:
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
render plain: "Hello, World!"
# 例3. リダイレクトヘッダーを設定:
response.headers["Location"] = "https://example.com/new_page"
render status: 302, plain: "Redirecting..."
end
end
改行コードを適切に処理するヘッダ出力用 API を利用できない場合は改行を禁止し、開発者自身で適切に処理する
改行の後に空白を入れて継続行として処理したり、改行コード以降の文字列を削除したり、改行が含まれていたら Web ページ生成処理を中止したりする
保険的対策
外部からの入力の全てに対して改行コードを削除する
外部からの入力全てから改行コード・制御コードを削除する。
<textarea>
タグも一律にやってしまうと、正しく動かなくなるので注意が必要。
メールヘッダ・インジェクション
概要
Web アプリケーションの中には、特定のメールアドレスをメールを送信する機能を持つものがある。通常、管理者により固定の宛先に送信されるが、実装によっては外部のものがこのアドレスを自由に指定できてしまう場合がある。
これを悪用した攻撃を『メールヘッダ・インジェクション』と呼ぶ。
発生しうる脅威
脅威 | 具体例 |
---|---|
メールの第三者中継 | 迷惑メールの送信に悪用される |
問い合わせページやアンケート等の利用者が入力した内容を管理者宛にメール送信する機能を実装しているサイトが影響を受ける。
根本的解決
メールヘッダを固定値にして、外部からの入力はすべてメール本文に出力する
下記のケースでは、メールヘッダ内に余分な改行が含まれる状況で悪用の原因となる。
- 『To』、『Cc』、『Bcc』、『Subject』等のメールヘッダの内容が外部からの入力に依存する場合、
- メール送信プログラムの出力に問題がある場合
メールヘッダを固定にできない場合、Web アプリケーションの実行環境や言語に用意されているメール送信用 API を用いる
メールヘッダを固定できない理由の一つに『メールの件名を変更したい』という場合がある。外部からの入力をメールヘッダに出力する場合、Web アプリケーションの実行環境や言語に用意されているものを利用するとよい。
class MyMailer < ApplicationMailer
def my_email
mail(to: "recipient@example.com", subject: "My Subject") do |format|
format.text
format.html
end
# メールヘッダーを設定
headers["X-Custom-Header"] = "Custom Header Value"
end
end
HTML で宛先を指定しない
Web アプリケーションに渡されるパラメータ(やってはいけないが hidden, 宛先をそのまま)に宛先を指定する実装は、パラメータ攻撃よりメールシステムの第三者中継につながる可能性がある。
保険的解決
外部からの入力の全てについて、改行コードを削除する
外部入力について改行コード(必要に応じて制御コードも)を削除する。
クリックジャッキング
概要
ログイン機能を有し、ログインユーザのみ使用可能な機能を提供している Web サイトにおいて、マウス操作にて細工された外部サイトを閲覧・操作することで、利用者の意図しない機能の実行をさせられる可能性がある。この攻撃のことを『クリックジャッキング攻撃』と呼ぶ。
発生しうる脅威
脅威 | 具体例 |
---|---|
ログイン後の利用者のみが利用可能なサービスの悪用 | 意図しない情報発信/退会処理 |
ログイン後の利用者のみが編集可能な設定の変更 | 利用者情報の意図しない変更 |
マウス操作のみで実行可能な処理に限定されるのが『クリックジャッキング攻撃』であり、脅威の内容は CSRF 攻撃と同じ。
根本的解決
HTTP レスポンスヘッダに
X-Frame-Options
ヘッダフィールドを出力し、他ドメインサイトからのframe
要素やiframe
要素の読み込みを制限するX-Frame-Options
は他のドメインからframe
,iframe
要素の読み込みを制限するために使用できるセキュリティヘッダー。レスポンスヘッダーに下記のように設定することで読み込みを制限できる。設定値 frame
,iframe
要素の表示できる範囲DENY
全ての Web ページでフレーム内の表示を禁止 SAMEORIGIN
同一オリジンの Web ページのみフレーム内表示を許可 ALLOW-FROM
指定したオリジンの Web ページのみフレーム内表示を許可 X-Frame-Options
の Ruby on Rails での設定方法:
module AppName
class Application < Rails::Application
config.action_dispatch.default_headers = {
# 同一オリジンのみ `frame`, `iframe` 要素の読み込みを許可
'X-Frame-Options' => 'SAMEORIGIN'
}
end
end
他にも Content-Security-Policy
(CSP) でも設定が可能。CSP はページ内で許可されるリソース制御を提供する包括的なセキュリティヘッダー。
X-Frame-Options
は frame
, iframe
に対してのみの設定であったが、CSP
は多くの柔軟性と細かい制御を提供し他のセキュリティポリシーと一元的に管理できる。今日では CSP
が主で利用されるらしい。参考
CSP
の Ruby on Rails での設定例:
module AppName
class Application < Rails::Application
config.action_dispatch.default_headers = {
# 同一オリジンのみ `frame`, `iframe` 要素の読み込みを許可
'Content-Security-Policy' => "frame-ancestors 'self'"
}
end
end
CSP の細かな設定方法はContent-Security-Policy:構文を参照。
処理を実行する直前のページで再度パスワード入力を求め、実行ページでは再入力されたパスワードが正しい場合のみ処理を実行する
処理実行前にパスワード認証することでクリックジャッキングの脆弱性を解消できる。一方で画面設計使用等を変更する必要がある点に注意。
保険的対策
重要な処理は、一連の操作をマウスのみで実行できないようにする
クリックジャッキング攻撃は、視覚的に騙して特定の操作を誘導する。よって、利用者に複雑な操作をさせることは難しいため、マウス操作のみで処理が実行されないようにキーボード操作を挟むことで攻撃の成功率を低減できる。
バッファオーバーフロー
概要
あらゆるプログラムは、指示された処理を行うためにメモリ上に自身の使用する領域を確保する。プログラムが入力されたデータを適切に扱わない場合、プログラムが確保したメモリの領域をオーバーし、領域外のメモリを上書きされ、意図しないコードを実行してしまう可能性がある。この攻撃のことを『バッファオーバーフロー攻撃』と呼ぶ。
発生しうる脅威
脅威 | 具体例 |
---|---|
プログラムの異常終了 | 意図しないサービス停止 |
任意のコード実行 | ウイルス、ワーム、ボットへの感染、バックドアの設置、他システムへの攻撃、重要情報の漏洩 |
バッファオーバーフローは、C や C++, アセンブラ等の直接メモリを操作できる言語で記述されている場合に発生する。Ruby は自動メモリ管理を提供するため、プログラマが明示的にメモリ管理を行う必要はない。
根本的解決
直接メモリにアクセスできない言語で記述する
直接メモリ操作できない言語で Web アプリケーションを記述することで、バッファオーバーフローの作り込みを防止できる。Web アプリケーションの多くのは直接メモリ操作できない言語(Ruby, PHP, Java, Perl 等)で記述されている。
直接メモリにアクセスできる言語で記述する部分を最小限にする
C, C++, アセンブラなどの直接メモリにアクセスできる言語を記述する部分を最小限にし、バッファオーバーフローがないことを集中的に確認する。
脆弱性が修正されたバージョンのライブラリを使用する
一般的に古いライブラリはバッファオーバーフローの脆弱性が存在する場合があるため、脆弱性が修正されたバージョンを使用する。
アクセス制御や認可制御の欠落
不適切な設計で作成された Web サイトは、『アクセス制御』や『認可制御』等の機能欠落に伴う脆弱性がある。以降ではそれへの対策をまとめる。
『アクセス制御の欠落』への根本的解決
アクセス制御機能による防御装置が必要とされる Web サイトには、パスワード等の秘密情報の入力を必要とする認証機能を設ける
Web サイトで非公開とされるべき情報を扱う場合や、利用者本人のみデータ変更や編集を許可することを想定する場合、アクセス制御機能*2の実装が必要。
『認可制御の欠落』への根本的解決
認証機能に加えて認可制御の処理を実施し、ログイン中の利用者が他人になりすましてアクセスできないようにする
Web サイトにアクセス制御機能を実装して、利用者本人のみデータ閲覧や変更等の操作を許可する際に、複数利用者の存在を想定する場合、どの利用者にどの操作を許可するかを制御する、認可(Authorization)制御の実装が必要となる場合がある。