初心者データサイエンティストの備忘録

調べたことは全部ここに書いて自分の辞書を作る

クロスサイト・リクエスト・フォージェリとディレクトリ・トラバーサル

クロスサイト・リクエスト・フォージェリとディレクトリ・トラバーサルについて勉強しました。本記事はこれらの攻撃についてまとめています。なお、私はセキュリティに関してはずぶの素人で本記事にも誤りが含まれているかもしれません。その際はコメントでご指摘いただけると幸いです。

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

どんな攻撃?

セッションが確立した状態で罠のリンクを踏むことにより、意図しない操作が実行されてしまう攻撃です。

どうやって攻撃するの?

攻撃者は罠のリンクを作成し、掲示板等に貼り付けることによって攻撃の準備をします。実際にセッションが確立された状態の人が罠のリンクを踏まない限り攻撃は成立しません。

被害者が図1のようなステップを踏んでしまうことで攻撃を受けてしまいます。

図1:クロスサイト・リクエスト・フォージェリの攻撃を受けるまでのステップ

どんな影響があるの?

脆弱性体験学習ツール AppGoat:IPA 独立行政法人 情報処理推進機構によれば、下記の影響があります。

  • ログインしたユーザのみが利用可能なサービスの悪用
  • ログインしたユーザのみが編集可能な情報の改ざん

対策

重要な処理の前に認証を行うことが対策となります。対策として、AppGoatには下記の3点が記載されていました。

  • 重要な処理の前に再度パスワードを要求する
  • 重要な処理をするページがどこからリクエストされたのか確認し、正規のリクエスト元からのリクエスト以外は全て拒否する(リファラーの確認)
  • 重要な処理を要求するリクエスト送信側でトークンを発行し、処理実行側でトークンが正しいか確認する。トークンが正しくなければ、リクエストを拒否する。

ここでは、上記の対策の3番目のトークンを確認する方法について説明します。

まず、リクエスト送信側ではトークンを発行します。トークンは下記のスクリプトで発行できます。

<input type="hidden" name="token" value="<?php echo session_id()?>">

ポイントはsession_id()を使うことです。これにより、リクエストを送るたびに異なる乱数が設定され攻撃者にトークンが漏洩することが防げます。

次に、処理実行側ではトークンが正しいかを確認する処理を行ってから、重要な処理を行うようなスクリプトにします。

if(session_id() === $_POST["token"]){
    # 重要な処理
}

これにより、正しいトークンが発行されたときにしか重要な処理を行えないようにでき、クロスサイト・リクエスト・フォージェリを防ぐことができます。

ディレクトリ・トラバーサル

どんな攻撃?

WEBサーバ上で公開されていないファイルを閲覧したり、削除するなどの攻撃をすることです。

どうやって攻撃するの?

WEBページの入力値やリクエストに含まれるパラメータに相対パスを設定することで攻撃を行います。

ディレクトリの階層が図2のようになっているとします。

図2:ディレクトリ構造

このとき、入力値に

../../../../secret_dir/secret.txt

などと設定することで、本来公開されていないsecret.txtを閲覧するなどの攻撃を行うことができます。

どんな影響があるの?

AppGoatによれば、攻撃により下記の影響が発生するようです。

  • 公開されていないWEBサーバ内のファイルを閲覧される
  • 公開されていないWEBサーバ内のファイルを削除、改ざんされる

対策

URLに含まれるパラメータを直接参照しないような処理を挟むことによって、ディレクトリを直接指定できない状態にします。

PHPのbasename()を使う方法について記述します。basename()はディレクトリを指定しても、ファイル名だけを取り出す処理をするメソッドです。 例えば、下記のような挙動をします。

basename("../../../../secret_dir/secret.txt") 
# "secret.txt"を返す

これを使って脆弱性のあるコードを修正します。

# 脆弱性のあるコード
readfile(TMPLDIR .$_GET['template'])

上記のコードは入力されたURLのディレクトリ指すパラメータ'template'を直接参照しており、ディレクトリ・トラバーサルの脆弱性があります。このコードをbasename()を使って下記のように修正します。

# 修正したコード
$file_name = basename($_GET['template'])
readfile(TMPLDIR .$file_name)

これにより、例えば_GET['template']="../../../../secret_dir/secret.txt"だとしてもreadfile(TMPLDIR "secret.txt")となります。このようにすることで、WEBページと同階層上にsecret.txtが存在しない限りはsecret.txtを閲覧される恐れがなくなります。

まとめ

今回はクロスサイト・リクエスト・フォージェリとディレクトリ・トラバーサルについてまとめました。前回記事に記載したXSSSQLインジェクションや今回記事にした攻撃を振り返ってみると、WEBアプリケーション上の入力値には危険なものが多くあることを知りました。また、入力値を直接参照せず、何らかの処理を挟むことでこれらの攻撃を防ぐことができることも学ぶことができました。 今後も各攻撃の共通点や相違点を意識しながら勉強していきたいと思います。

※前回記事

aisinkakura-datascientist.hatenablog.com