スクレイピングしてくる不届きものを、AWS WAFを使ってブロックする話

# 概要
Webの集客をGAで監視していたところ、異様なトラフィックの増加が見られたので、スクレイピングされてるのでは…？と、対策することになったお話です。

Headless Chromeだけ弾く、とかいろいろ考えましたが、調べると現実的ではなさそうで、まずは、WAFで止めましょうという流れになりました。

# 結果
いくつかスクレイピングしてるだろう不届き者のIPを発見し、ブロックしてさしあげました。

やった処理は以下の通りです。

1. 一定時間のアクセスが多すぎるIPを一時的に弾く
2. BlackリストにいれたIPを弾く
3. Whiteリストに入れたIPはBlackリストに引っかからないようにする

以下の図は、PV数を時間毎に表示したものですが、対策後の山が僅かに小さくなっていること、気づけますでしょうか？
（分母がそれなりに大きいので差分が分かりづらいですが）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/8f085ec4-642d-0ff2-02d2-13088179604f.png)

# WAF（Web Application Firewall）
WAF（ワフ）は、Webアプリケーションの脆弱性を狙った攻撃からWebサイトを保護するセキュリティ対策です。
Webサーバーの前段に設置して通信を解析し、不正なアクセスを弾きます。

# AWS WAF
設置の仕方としては以下の設置方法があります。
①Cloud Frontの前段に設置して、Cloud Frontへのアクセスを監視する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/b217f342-d497-3860-efbb-ddc4eb34968c.png)

②Cloud FrontとELB(ALB)の間に設置して、Cloud FrontからELBのアクセスを監視する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/54656335-f843-2340-3dc4-461aa6d6fbbd.png)

③Route53とELB(ALB)の間に設置して、Route53からELBのアクセスを監視する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/1edc19b4-9ccd-c115-bcce-7e70f848e6d6.png)



ELBと同様にAPI Gatewayにも適用できます。

# 構成
今回のざっくりした構成はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/c0e7a514-0589-dbfa-3b6d-1d13c3ec5f5a.png)

# 実装① 一定時間のアクセスが多すぎるIPをブロックする
AWSのコンソールを開いて、WAFと検索すると、「WAF & Shield」というページが見つかるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/e81d8b99-5528-fbe0-3af1-7cd2569b1608.png)

まず、最初にやることなのですが…
今回弾きたい対象に、cssやjsなど、Asset周りを含めるつもりはありません。
なので、その設定をおこなえるように、正規表現をあらかじめ作成しておきます。

正規表現のページから新規作成を行って行きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/efb3c975-314d-26a8-c7b9-e39feaa3382b.png)

名前は分かりやすいものをつけて、弾きたかった`/image/``/fonts/` `/assets/`を含めてくれるような正規表現を記載すれば完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/cb80138a-8b60-a4ad-d17d-a24335b34a2d.png)



Web ACLsページからACLの新規作成に進みます。
※ACL: Access Control List --> IPに対してのルールをまとめたグループみたいなものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/0461149e-ef96-16d5-b43b-651958cd642d.png)

名前を入力します。名前を入れると自動的にCloudWatchのメトリクス名が入力されます。
※メトリクスも説明しておくと、CloudWatchはいくつもの情報の点を集積させてログを残していく仕組みなのですが、その点情報のグループにあたるものがメトリクスだと考えてもらえばいいかと。

リソースタイプの項目でCloudFrontに対して設置するのか、ELBまたはAPIGatewayに対して設置するのかを選択できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/a714f119-bf56-abec-4261-c653de7544f1.png)

下段で、WAFに紐付けたいリソースを紐付けします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/9ac5d286-9839-a56e-2416-9368e9d3e830.png)


次のページでルールを設定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/71de4ab6-8963-dbf1-93a5-2df5a3e62639.png)

最初に実装したいのは、「一定時間のアクセスの多いIPを弾く」処理です。
「Add my own rules and rule goups」をまずクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/fd87a6a4-5b74-6655-696f-893f34bd1c88.png)

IPListを使う処理ではないので「Rule builder」を選択します。

「Type」は「Rate-based rule」にします。
こうすることで、5分間のアクセスの数を設定することができます。
下段の詳細設定に許可するアクセス数を入力するだけです。
※100から設定できます。

詳細設定にあるラジオボックス。
これが以外と重要なのですが、**「Consider all request」を選択してしまうと、すべてのIPに対してこのルールを適用してしまう**ことになります。
冒頭にも書きましたが、Asset周りのアクセスを同時にカウントして欲しくはないですよね。
ですので、「Only consider requests」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/4ba218cf-a022-830c-2d8f-ba0567b77b43.png)

そして、その次の段にでてくる設定で、正規表現に一致しないという条件を入れ、作った正規表現のパターンセットを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/c30759d2-5ec9-fc9b-a32d-ed1e55a1a2e1.png)

最後に、この条件に合う（五分間に指定した回数以上のアクセスがあった）場合にブロックするのか、またはカウントするだけなのかを選択すれば設定完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/7a5cfc21-6e36-a7fd-c833-f3c3a7142db3.png)

### 実装の結果

でてくるでてくる。不届き者達。
最初びっくりさせられたのは5分間どころか10秒で500アクセスぐらいしてきてたIPがあったり。
（逆によく耐えてたな…サーバー）

↓WAFのACLsのダッシュボードです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/448b433c-1ff6-8679-71f6-e0a9020f897a.png)

ブロックしたメトリックス（こちらもWAFのACLsのダッシュボード）を確認すると、どうやら同じIPが、順番にページを叩いていっているのが見える状況……
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/09f733ed-7610-77a5-cd7b-323961a05b10.png)


上手くいってるようにみえますが、ここで、もう一つ**課題**があります。

会社によっては同じルーターから外部にアクセスする場合が多いため、**同じ場所の複数の人間が同時間にアクセスしてもこのルールに引っかかってしまう場合がある**のです。
なので、あまり厳しい回数制限はできません。

そんなこんなで新たに以下の実装を加えるわけです。

1. あからさまなクローラーはBlackリストへ
2. 顧客になりそうなIPはWhiteリストへ
3. 検索エンジン関連のクローラーはWhiteリストへ

# 実装② Blackリスト/Whiteリストの作成
まずは、IPがどこのものか調べます。
BlockされたIPを見て、これはAWSのサーバーだとか、これは某企業のサーバーだとか、仕分けします。

ページを順番に叩いていっている、サーバーっぽいIPは、Blackへ登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/80c69ff2-4247-1749-aae2-42b7fbbff6d1.png)

名前をつけて、対象としたいIPを改行しながら追加していけばリスト完成です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/fb16d3f7-1e6f-09bb-3dd2-ea5f90f962c6.png)
Whiteリストも同様の方法で作成します。

再度、Web ACLsのページに入り、Rulesからルールの追加をします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/8f2a7fc4-8a85-c5e3-decd-5241281f8202.png)

今回は、IPリストを使うので、IPsetを選択します。

Blackリストであれば、IP setに先ほど作ったBlackリストのセットを選択し、Blockに。
Whiteリストであれば、Whiteリストのセットを選択し、Allowを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/afef3315-aa1d-5dc7-3a93-37573f3ad62b.png)

そして、ルールの優先度を
`Whiteリスト → Blackリスト → 一定時間ルール`
にすれば完成です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270964/64afb931-8452-c1ce-a112-4b1bbc596f6f.png)

### 実装の結果
Blackリストに入れたIPがしつこくアタックしてくるのが良くみえ、とても愉快な気分になりました。


# 実装してみて
たまに人力でIPを確認してやらないといけないので（ルールに引っかかってブロックされたものがあればメールで飛ばすようにしてますが）運用に少しだけ負荷がかかりますが、大事なデータを簡単にとられないようにするという目的はある程度達せられたのではないかなという感じです。