はじめに
AWS WAFがCloudFrontだけでなくELBでも使えるようになり、より使いやすくなりました。
そこで、SQLインジェクションや非公開ファイルへのアクセスをブロックし、WAFのメリットを確認していきましょう。
AWS WAFとは
AWS WAF(Web Application Firewall)は、脆弱性を利用した様々な攻撃からアプリケーションを保護するファイヤーウォールです。
多くのAWSサービスと同様に、料金は従量課金となっています(設定するルール数、アプリケーションへのリクエスト数によって変動)。
脆弱性を持ったアプリケーション
まずはテストのために、SQLインジェクションが可能なRailsアプリケーションを作成します。
普通にRuby on Railsでアプリケーションを作ると基本的なリスクヘッジがされていますが、ここではあえて脆弱性を含むコードを書いてみます。
Userモデルに名前とメールアドレスのカラムが存在するという状態で、入力したメールアドレスと一致するユーザを検索をするために、プレイスホルダを使わずに文字列をそのままSQLとして渡すself.search_unsafe
というメソッドを作成します。
[ruby]
class User < ApplicationRecord
# 危険
def self.search_unsafe(email)
User.where("email = '#{email}'")
end
# 安全
def self.search_safe(email)
User.where("email = ?", "#{email}")
end
end
[/ruby]
このメソッドに、
[sql]
' or 1=1 --'
[/sql]
という文字列を入力すると、発行されるSQLは
[sql]
SELECT `users`.* FROM `users` WHERE (email = '' or 1=1 --'')
[/sql]
となり、意図せず全てのユーザリストが取得できることになります。
AWS WAF
このRailsアプリケーションをEC2にデプロイし、ELB配下に設置します。
AWSマネジメントコンソールからWAFを選択。
Web ACLの作成を行います。
Web ACLの名前、CloudWatchのmetric名、対象となるELBを指定します。
Webアクセスコントロールリストを作成します。
今回はSQLインジェクションとURLに特定の文字列を含む場合をブロックするので、まずSQL Injection match conditionsを選択します。
名前を入力し、今回はフィルターにPart of request to filter onを「Body」、Transformationに「URL decode」を選択します。
同様にString match conditionを作成します。
名前、Part of request to filter onは「URL」、Match Typeを「Contains」、Value to matchに「secret」を設定します。
これで、secret.htmlなどを含むURLが要求された時にはブロックされるはずです。
次にルールを作成するため、「Create rule」を押します。
名前とCloudWatchのmetric名を入力し条件を設定します。
今回作成したルールは以下の通りです。
- SQLインジェクションをブロック
- 特定文字列に一致したものはブロック
- それ以外は許可する
この内容で作成を実行します。
たったこれだけで、ELBにWAFが適用されます。
/secret.htmlにアクセスしてみると、確かにELBがブロックしています。
SQLインジェクションも検索実行した後に危険な文字列が含まれているためブロックされます。
マネジメントコンソールで確認してみると、WAFがブロックした履歴が確認できます。
まとめ
CloudFrontを使用していないケースでもELBでWAFが使えるということは、従来からあるアプリケーションにも適用可能となるので導入のハードルが下がりました。
アプリケーション特性に合ったルールが設定できるので、AWSでアプリケーションを運用する際にはWAFを検討してみてください。