2022年12月現在、「Mod_Securityが検知したIPアドレスネガティブリストに放り込む」は達成しました。
- これら検知したIPはどこの国からか?
- 日々、どのぐらいの数、不審なアクセスが来ているのか?
を把握するため、シェルスクリプトを書きました。(今回で一端終了です)
やりたいこと
- Mod_securityが検知したエラーログからIPアドレスのみを抜き出す
- 検出したIPアドレスがどこの国からアクセスしたかを調査してcsvファイルに出力する
- 同じIPアドレスごとに件数を数え、降順で並べ替える
- cronで定期実行する
本項でやること
- cronで定期実行
前提
- エラーログからIPアドレスを抜き出しアクセス元の国を抜き出すスクリプト
- そのIPアドレスをカウントして降順に表示するスクリプト
また、
- apacheのログが日ごとにローテーションされていること
- redmineの稼働サーバに導入しているので、ログ表示プラグインで閲覧できる
も想定しています。
スクリプト作成
cron用に一部手を加えます。
エラーログからIPアドレスを抜き出してアクセス元の国を付与
ip_check.sh
スクリプト内容
#!/bin/bash
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# ログの格納場所に移動
cd /var/lib/redmine/log
# error.logからIPアドレスだけを抜き出します
cat ./error.log | awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print substr($0, RSTART, RLENGTH) }' | sort > ip.`date +%Y%m%d`.csv
listfile="./ip.`date +%Y%m%d`.csv"
# ip.YYYYMMDD.csvファイルがない場合にエラーを返します
if [ ! -f $listfile ]; then
echo "ファイル $listfile が存在しないので終了します。"
exit 1
fi
country_list="./country_list.csv"
# 国コード,国の名前が書かれたcountry_list.csvがない場合にエラーを返します
# このCSVファイルはログの格納場所に配置します
if [ ! -f $country_list ]; then
echo "ファイル $country_list が存在しないので終了します。"
exit 1
fi
# IPアドレスに国名を付与したファイルを定義します。(ip_list.YYYYMMDD.csv)
result_file="./ip_list.`date +%Y%m%d`.csv"
cat /dev/null > $result_file
cat ${listfile} | while read line
do
# IPアドレスを逆順に並び替えます。(例: 1.2.3.4 → 4.3.2.1
ip_revers=`echo ${line}|awk -F'.' '{print $4,".",$3,".",$2,".",$1}'|sed -e 's/ //g'`
# 並び替えたIPアドレスをcc.wariate.jpに並び替えて、国コードを抜き出します。(JP,CH,ESなど
country_code=`nslookup -type=TXT ${ip_revers}.cc.wariate.jp | grep '"'|awk -F'"' '{print $2}' `
# 国コードをcountry_list.csvから参照して国名を抜き出します。
country_name=`cat ${country_list} | grep ${country_code} | cut -d"," -f 2`
# 次の行は標準出力に返す処理を行います。cron処理する場合は#をつけて作動しないようにします。
# echo "${line},${country_name}"
# IPアドレス,国名の形式にして同ディレクトリのip_list.YYYYMMDD.csvに保存します
echo "${line},${country_name}" >> $result_file
sleep 1
done
chown www-data:www-data ip.`date +%Y%m%d`.csv
chown www-data:www-data ip_list.`date +%Y%m%d`.csv
exit
アクセス元の国を付与したリストを集計するスクリプト
ip_count.sh
スクリプト内容
#!/bin/bash
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
cd /var/lib/redmine/log
# ip_list.csv.YYYYMMDDを読み込んで、IPアドレスをキー、国を値とする連想配列を作成します
declare -A countries
while read -r line; do
# CSVの1列目をIPアドレス、2列目を国とします
ip=$(echo $line | cut -d',' -f1)
country=$(echo $line | cut -d',' -f2)
# 連想配列に格納します
countries[$ip]=$country
done < ip_list.`date +%Y%m%d`.csv
# 結果を格納するための変数を定義します
result=""
# 連想配列を反復処理します
for ip in "${!countries[@]}"; do
# 各IPアドレスの件数を数えます
count=$(grep -c $ip ip_list.`date +%Y%m%d`.csv)
# 件数、IPアドレス、国をカンマ区切りで結合します
line="$count,$ip,${countries[$ip]}"
# 結果に追加します
result="$result\n$line"
done
# カウントした結果をcounted_ip.YYYYMMDD.csvに出力します
echo -e $result > counted_ip.`date +%Y%m%d`.csv
### ↑ここまでchatGPTが作成したスクリプト↑ ###
# 最終結果をsorted_ip.`date +%Y%m%d`.csvに出力します
# LC_ALL=Cを設定しないと日本語で書かれた国名の並べ替えがうまくいきませんでした
cat counted_ip.`date +%Y%m%d`.csv |LC_ALL=C sort -n -r > sorted_ip.`date +%Y%m%d`.csv
# 最終結果以外のログファイルを削除します
# 必要に応じて無効化してください
rm ip.`date +%Y%m%d`.csv
rm ip_list.`date +%Y%m%d`.csv
rm counted_ip.`date +%Y%m%d`.csv
chown www-data:www-data sorted_ip.`date +%Y%m%d`.csv
exit
Cron配置
sudo crontab -e -u root
定期実行
0 7 * * * /スクリプト配置パス/ip_check.sh && /スクリプト配置パス/ip_count.sh
これで、指定した時刻に
- IPアドレスの抜き出し
- IPアドレスの集計
を行うようにしてくれます。