Google Apps Script でアラートメールを分析

# はじめに
最近とりわけサイバー攻撃が増えていますね。クライアントに設置しているFortigateから毎日かなりの数のアラートが届きます。社内から「毎回報告書を作るのが大変」との声が出たので，GASを使ってアラートメールをスクレイピングして「何件あるか」「どこからの攻撃か」がわかるようにしました。

# 使ったもの
* Gmail
* Google スプレッドシート
* Google Apps Script
* GeoLite2（IPから国情報を取得）
* LINE Notify（分析完了時の通知）

# 取得する内容
来るアラートはこんな感じです。
```
Message meets Alert condition
The following critical firewall event was detected: SSL VPN login fail.
date=2022-**-** time=00:00:01 devname=<<DEVNAME>> devid=<<DEVID>> logid=<<LOGID>> type=event subtype=vpn level=alert vd=root logdesc="SSL VPN login fail" action="ssl-login-fail" tunneltype="ssl-web" tunnelid=0 remip=<<攻撃元IPアドレス>> user="<<USER>>" group="N/A" dst_host="N/A" reason="sslvpn_login_unknown_user" msg="SSL user failed to logged in"
```
上記アラートから
* 日付：受信日時
* メールタイトル
* メッセージ：msg=
* 攻撃元IPアドレス：remip=
* 国情報

を取得し，最終的には以下のようなシートを作るようにします。グラフは後から手動で付けてます。（ここもそのうち自動化する予定）
![logsheet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1675445/b15c65d6-b48d-2859-5a6b-b86aea5667a3.png)
ロシア多いな…

# IPアドレスと国情報の取得
メールの受信日時は`getDate()`を，タイトルは`getSubject()`を，メールの文面は`getPlainBody()`を使えばいいので特に苦労しませんでした。

IPアドレスは正規表現で取得できます。
```JavaScript:
// リモートIPアドレス取得
const Regex = /(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/;
const IPAddr = PlainBody.match(Regex);
```
配列で返ってくるので，文字列を取得するには`IPAddr[0]`としてあげる必要があります。

今回は「どこからの攻撃か」を知りたいので，[GeoLite2](https://www.maxmind.com/en/geoip2-services-and-databases)を使ってIPアドレスから国情報を取得します。事前にサインアップしてIDとトークンを取得しておく必要があります。[GeoLite2 サインアップページ](https://www.maxmind.com/en/geolite2/signup)

```JavaScript
// GeoLite2 Options
const ID = "<<GeoLite2のID>>";
const PW = "<<GeoLite2のトークン>>";
const option = {
  'method': 'GET',
  'contentType': 'application/json; charset=utf-8',
  headers: {"Authorization" : " Basic " + Utilities.base64Encode(ID + ":" + PW)}
}

// IPアドレスから国を取得(GeoLite2使用)
const url = 'https://geolite.info/geoip/v2.1/country/' + IPAddr[0] + '?pretty';
let res = UrlFetchApp.fetch(url, option);
let conData = JSON.parse(res);
let txtCountry = conData["country"]["names"]['ja'];
``` 
あとGeoLite2は無料なので __1日あたり1000件までしかリクエストできない__ ことに注意してください。（超える場合は有償を考慮）

今回は1ヶ月分まとめてリクエストするとすぐ上限に行きそうだったので，毎日定時でスクリプトを動かすことにしました。

# 定時実行
GAS にはトリガーが設定できるので，毎日朝7～8時に前日のアラートメールを収集するよう設定します。
![cron.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1675445/c7ba904d-83e9-35c2-830e-7ba7c3bd70a7.png)

# せっかくなのでLINE通知
[LINE Notify](https://notify-bot.line.me/ja/)を使えば難しいことなく自分のLINEに通知できるので活用することにします。日付を引数で渡していつの分析が済んだかわかるようにします。

```JavaScript
function sendLINENotify(RunDate) {
  
  const Mes = RunDate + "分のFortigateのアラート分析が完了しました！";
  
  // LINE Notify Token
  const Token = "<<取得したトークン>>";

  const options = {
    "method": "post",
    "headers": {
      "Authorization" : "Bearer "+ Token
    },
    "payload": {
    "message": Mes
   }
  }

  const url  = "https://notify-api.line.me/api/notify"
  UrlFetchApp.fetch(url, options)

}
```
# 感想
GASでのメールスクレイピングは初めてやりましたがすごく便利ですね。受注メールから在庫管理システムへデータ渡したり，売り上げ出したり…できること多くて面白いです。

「かゆいところに手が届く」身近なシステム屋さんを目指してますので是非お仕事・ご相談お待ちしております😄

# 謝辞
以下のサイトを参考にさせていただきました。ありがとうございます。
https://tetsuooo.net/gas/746/
https://note.com/skipla/n/nefdfa2abd350