AWS WAF完全に理解した

いつもお世話になっております。Azoopの武田です。
ここ3ヶ月エオルゼアで毎週1回某お母様と戦い続けて欲しかった白魔道士の杖が取れました。

さて弊社のプロダクトである運送業務支援サービス『トラッカーズマネージャー』(以下、トラマネ)ですが、お客様である運送会社の車両やドライバーの情報といった大切なデータを預かり、また輸送案件の管理や請求書発行など基幹業務を担わせていただいています。
ブラウザ経由で使うという性質上インターネットという広大で物騒な世界に露出しており、ログ上でも既知の脆弱性を元にした攻撃や攻撃の足掛かりを探す不審なアクセスを観測しています。
弊社のプロダクトに攻撃を仕掛けてくる悪い人たちをレイドの時間切れを迎えた光の戦士たちと同じように

『渦なす生命の色、七つの扉開き、力の塔の天に至らん!』

と魔法一撃でワイプできたらいいのですが、この世界にはそんな都合のいいものはないのでトラマネではウェブアプリケーションファイアウォール(WAF)を導入して防御を固めています。

WAF

WAF(Web Application Firewall)とはHTTPリクエストのヘッダやボディの内容を監視し脆弱性を突いた攻撃を防ぐセキュリティ対策です。例えばウェブアプリケーションセキュリティの教科書の最初ほうに載っているような「フォームにスクリプトタグを仕込む」というような単純なXSSから世界中を震え上がらせた(?)Log4j脆弱性のような既知の脆弱性を使った攻撃を防いでくれます。
弊社ではプロダクトのインフラとしてAWSを使っており簡単に導入できることからAWS WAFを使用しています。

AWS WAF

WAF自体はF5やImpervaなどのセキュリティベンダーからEC2で動かすためのAMIがAWS Marketplaceを通してリリースされており、慣れていたりより詳細に設定したいといったニーズには対応できますが専門的な知識がないと構築も難しく私を含めWAFについてあまり詳しくないメンバーで運用するにはハードルが天に届く勢いで高いです。
一方、AWS WAFを使うとALB, CloudFront, API GatewayとAppSyncのいずれかを使ってさえいればマネージメントコンソールから操作するだけで導入できるためそれだけでなんとか地上から見えるぐらいまでハードルを下げることができます。さらに後述するスコープダウンステートメントを設定するときのクセの強さはあるものの簡単な操作でルールやログの保管などの設定を行うことができます。また導入するルール自体もAWSが無料のマネージドルールセットとしてメジャーなものを用意しているのでそれをひとまず入れるだけでも対策の導入としては十分でしょう。
またAWS以外のもセキュリティベンダー各社がAWS WAF向けにAWS Marketplaceでマネージドルールセットを時間+リクエスト数による課金で販売しているので比較的安価に専門ベンダーの知見を取り入れることが可能です。

構成と運用

ではここでトラマネにおける構成と運用についてみていきます。

AzoopのWAF構成

トラマネはALBでリクエストを受けて後ろにFargateで動作しているRails製のアプリケーションサーバがいるというシンプルな構成になっています。(データベースその他のコンポーネントは省略)
Web ACLはステージング(QA用)環境と本番環境で共有しており挙動を揃えることでステージング環境でWAFの挙動起因による不具合に早いタイミングで気付くことができるようにしています1

ルールセット

Web ACLに設定しているルールはAWSマネージドルールといくつかの独自ルールを組み合わせてセットしています。

一部を抜粋すると以下のとおりです。

AWSマネージドルールセットのうち最初の5つは様々なブログやサイトで「基本セット」として紹介されていることがあるものです。基本セットと紹介されるだけあってメジャーな攻撃は一通り網羅されています。これをIP評価ルールと組み合わせることで体感で半分以上の攻撃は防げています。
さらにトラマネは日本国内で利用されているお客様がほとんどのため一部の国を除き海外からのアクセスを遮断することで8割近い攻撃を防げるようになりました。ここで一部の国としたのは例えばアメリカを遮断するとGoogleのクローラーまで遮断してしまう & クローラーのみ通すとクローキングにあたり禁止行為に抵触する可能性があるためです。

クセが強いスコープダウンステートメント

AWS WAFは検査対象をスコープダウンステートメントで設定できます。
スコープダウンステートメントは「検査対象を決める条件」なので設定時はあるパスを除外したいときは「このパスは検査しない」ではなく「このパス以外は検査する」ように書く必要があります。1つだけならNOTの設定ができるので簡単にできますが複数のパスを除外したいときは少し面倒です。NOTは複数設定できないのでスコープダウンステートメントを設定するときにANDまたはORを追加しそれぞれのスロットの「Negate statement results」にチェックを入れることになります。

つまり、複数のNOTを書くにはド・モルガンの法則による変換が必要です……私は頭の中で組み立てるのが苦手なのでメモ用紙に書きながらやりました……!将来のアップデートでこのあたりをいい感じにできるようになることを期待したいと思います。

マネージドルールセットから一部を除外する

AWSが提供しているマネージドルールセットから一部のルールを除外したい場合もあるでしょう。ルールのアクションはその種類に関わらずラベルを付与するのでマネージドルールセットのアクションはCOUNTにして後続に付与されたラベルに対するアクションを決めるルールを追加します。独自ルールは数による課金もあるので細かくやりすぎると結構な出費になることがあるので必要最小限に抑えるようすると運用にもお財布にも優しいです。

WAFのログ

弊社ではログは基本的にDatadog Logsに集約しており、AWS WAFのログもS3を経由してDatadogに流すことで検索できるようにしてあります。Datadog LogsはデフォルトでAWS WAFが出力するログをパースできるようになっているのでとりあえず流せば簡単に検索できるようになります。
AWS WAFは何も設定しないとすべてのアクションのログが送信されてくるので膨大な量になり検索性やお財布を大変痛めつけることになります。そのためCOUNTとBLOCK, EXCLUDED_AS_COUNTのログのみ出力されるように設定しています。

お客様のアクセスに対して意図しないブロックが発生したときはDatadogを使ってログを検索しスコープダウンステートメントを追加するといった対策を実施できるようにしています。

まとめ

トラマネではAWS WAFやセキュリティ診断を活用してお客様の情報を守っています。誤検知が起きて意図せずお客様をブロックしてしまってもDatadog Logsを活用して素早く問題を発見し必要なアクションを取れるようにしています。

そしてタイトルで完全に理解したと言っていますがわからないことだらけなのでこれからもよりよい付き合い方を探し求めて行こうと思います。


  1. Web ACL単位でも課金が発生するためコスト削減の意味合いもあります
  2. これがないとセキュリティ診断からの通信はXSSSQLインジェクションなどの攻撃を含むのでWAFで遮断されRailsアプリケーションまで到達せず診断できないのです…