タグ: mod security Page 1 of 2

Mod_Securityが検知したIDの抜き出し。(awkワンライナー)

Mod_Securityが検知したセキュリティポリシーの判定に役立つ小技です。

環境

  • Mod_Security
  • Apache2.4

を連携させ、SecRules On / DetectOnlyにしています。

ログ表示例

[Wed Nov 01 14:12:12.213885 2023] [:error](中略) ModSecurity: Warning. Pattern match (中略) at ARGS:html. [file "/usr/share/modsecurity-crs/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf"] [line "308"] [id "941190"] [msg "IE XSS Filters - Attack Detected."] (略)

ここから、941190の部分のみを取り出します。

コマンド

awk '{match($0, /\[id "([0-9]+)"\]/, arr); if(arr[1]) print arr[1]}' ログファイル

コマンド実行例

awk '{match($0, /\[id "([0-9]+)"\]/, arr); if(arr[1]) print arr[1]}' /var/log/bookstack/bs_error.log | sort -u
# 更に重複を排除

実行結果

941180
941190
942170
942350

これらを除外するなり例外に加えるなどの処理を行う下地ができました。

AWS LightsailにBookStack構築。

BookStackの構築がうまくいき、「これは使えそうだ」と思ったので、AWS Ligtsail上に構築しました。

やったこと

サイト構築

上述した通りです。

ログローテーション設定

https://barrel.reisalin.com/books/bookstack/page/bookstack

/etc/logrotate.d/bookstackに

/var/log/bookstack/*.log {
        daily
        missingok
        ifempty
        copytruncate
        rotate 10
        compress
        create 0640 www-data www-data
}

を作成しました。

Mod_Security設定

既に動いているので使わない手はありません。

https://barrel.reisalin.com/books/bookstack/page/bookstackmod-security

で連携させました。

ロゴ/バナー設定

既に「BarrelGazer」というサイト名をつけたので、それっぽいロゴやバナーをAIに描写してもらいました。

使ってみての感想

Scrapboxのように階層で区別できる上に「本棚」というイメージがお気に入りです。

しかも、描写が速いのが特徴。あとはMarkdownの自動補完があれば言うことなしですが、そこはローカルで動かしているGrowi環境との連携です。

Torの出口ノードリストからのWebアクセスを遮断する設定。(Mod_Securityとの連携)

こちらの記事の続きとなります。

Torの出口ノードリストを抽出するスクリプトと、既に稼働済みの不審なIPアドレスをブロックするスクリプトを連携させます。

前提

こちらにあるように、

  • Mod_Security導入済み
  • エラー検知時にブロックする設定をバーチャルサイトに設定済み

となります。

また、先日の記事である、

  • Tor出口ノードリストを抽出スクリプトがCron化されているものとします。

スクリプト

  • negativelist.sh
#!/bin/bash

# 読み込むログのディレクトリとファイル名を変数指定
log_dir="/var/lib/redmine/log"
log_file="error.log"

# シェルスクリプトから抽出したTorの出口ノードリストを指定
tor_list_dir="/path/to/directory"  # tor_list.txtのディレクトリを指定
tor_list_file="sorted_ip_addresses$(date +%Y%m%d).txt"

# 除外するIPアドレスをファイルで指定
# 自分のNWなど、偽陽性を防ぐために記載したアドレスのリストです。
exclude_ips_file="/path/to/directory/exclude_ips.txt"

# ログファイルからIPアドレスを抽出して重複を排除し、ファイルに保存します。
cd "$log_dir"
awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print substr($0, RSTART, RLENGTH) }' "$log_file" | sort -u > "$log_dir/suspicious_ip/suspicious_ip.$(date +%Y%m%d)"
chown www-data:www-data "$log_dir/suspicious_ip/suspicious_ip.$(date +%Y%m%d)"

# 過去のIPアドレスを読み込んで重複を排除し、ファイルに保存します。
cat "$log_dir/suspicious_ip/suspicious_ip."2* | sort -u > "$log_dir/suspicious_ip_all.txt"
chown www-data:www-data "$log_dir/suspicious_ip_all.txt"

# 新たにリストに書き起こすと同時にTorの出口ノードリストを読み込んで重複を排除し、negativelist.txtに追加します。
cat "$log_dir/suspicious_ip_all.txt" "$tor_list_dir/$tor_list_file" | sort -u > /etc/apache2/sites-available/negativelist.txt

# 除外するIPアドレスをファイルから削除します。
while IFS= read -r exclude_ip; do
  sed -i "/$exclude_ip/d" /etc/apache2/sites-available/negativelist.txt
done < "$exclude_ips_file"

# Apacheを再起動します。
systemctl restart apache2.service

あとはこちらをroot権限でCron登録。

設定後の動き

以下のように動きます。

  1. 指定のログファイルからエラーとなったIPアドレスのみを抽出します。
  2. 全てのIPアドレスを統合し、重複を排除してsuspicous_ip_all.txtとして抽出します。
  3. suspicous_ip_all.txtとtor_list_fileを統合し、negativelist.txtとして作成します。(これらのIPアドレスからのアクセスに対しては全て403を返します)
  4. negativelist.txtから除外IPアドレスを取り除きます。
  5. Webサービスを再起動します。

ひとまず、WAFとの連携ができました。

Mod_Securityが検知したIPアドレスの自動遮断スクリプト・修正。

以下のスクリプトを修正しました。

このスクリプトの主な動き

  1. Mod_Securityが検知したエラーログからIPアドレスのみを抜き出す。
  2. 重複を排除した上でsuscpicious_ip.YYYYMMDD形式で保存。
  3. 全てのsuscpicious_ip.YYYYMMDDを統合する。
  4. ここからnegativelist.txtを作成する。
  5. negativelist.txtの中に疑陽性(自身のアクセス元)のIPを排除する。
  6. Webサービスを再起動する。

そうして、「一度でもMod_Securityが疑わしいと検知すれば、次回以降のアクセスを許さない」という、言わば“ONE OUTS”システムを採用しています。

この可読性を高めました。

スクリプトが動く前提

  • ApacheとMod_Securityを運用している。
  • 以下のように、「negativelist.txt」に記録されたIP全てをブロックするようにしている。

apacheバーチャルサイト設定の抜粋

# Mod Security
SecRuleEngine On
## ModSecurity有効化
SecRequestBodyInMemoryLimit 524288000
SecRequestBodyLimit 524288000
## ファイルのアップロードをできるようにします。
    # ネガティブリスト
    SecRule REMOTE_ADDR "@pmFromFile negativelist.txt" "phase:1,id:2,deny,msg:'Negativelisted IP address'"

修正したスクリプト

※ 教義・信仰に沿ったエディタで記載します。

  • negativelist.sh
#!/bin/bash
# このシェルスクリプトは、変数で定義したエラーログからIPアドレスを抽出し、
# suspicious_ipディレクトリに保存し、その後、特定のIPアドレスを削除して
# /etc/apache2/sites-available/negativelist.txtに書き込むものです。

# 読み込むログのディレクトリとファイル名を変数指定
log_dir="/var/lib/redmine/log"
log_file="error.log"

# 除外するIPアドレスをファイルで指定
exclude_ips_file="/path/to/exclude_ips.txt"

# IPアドレスを抽出して重複を排除し、ファイルに保存
cd "$log_dir"
awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print substr($0, RSTART, RLENGTH) }' "$log_file" | sort | uniq > "$log_dir/suspicious_ip/suspicious_ip.$(date +%Y%m%d)"
chown www-data:www-data "$log_dir/suspicious_ip/suspicious_ip.$(date +%Y%m%d)"

# 過去のIPアドレスを読み込んで重複を排除し、ファイルに保存
cat "$log_dir/suspicious_ip/suspicious_ip."2* | sort | uniq > "$log_dir/suspicious_ip_all.txt"
chown www-data:www-data "$log_dir/suspicious_ip_all.txt"

# 新たにリストに書き起こす
cat "$log_dir/suspicious_ip_all.txt" > /etc/apache2/sites-available/negativelist.txt

# 除外するIPアドレスをファイルから削除
while IFS= read -r exclude_ip; do
  sed -i "/$exclude_ip/d" /etc/apache2/sites-available/negativelist.txt
done < "$exclude_ips_file"

# Apacheを再起動
systemctl restart apache2.service
  • 除外するIPアドレスリスト

※ 教義・信仰に沿ったエディタで作成します。

  • exclude_ips.txt 記載例
192.168.0.1
172.28.0.1
# 一行ずつ記載

記載後の設定

  • スクリプトの所有者変更
sudo chown root:root negativelist.sh
  • スクリプトの実行権付与
sudo chmod 744 negativelist.sh
  • cron登録
sudo crontab -e -u root
  • cron内容
0 6 * * * /home/manualmaton/bin/negativelist.sh

これによって、スクリプトを変数化。他のサーバへの転用を行いやすくしました。

mod_securityが検知した不審なアクセスをufwで一括遮断。

あらまし

apacheにmod_securityを導入後、以下を実施しました。

  1. Mod_Securityが検知した不審なアクセスのうち、IPアドレスのみを抜き出す
  2. その抜き出したIPアドレスをMod_securityによってブロックする
  3. これを日次で追加していく

この方法はそこそこうまくいっています。ですが、「これら不審なアクセス元はWebだけでの攻撃だけか? メールやSSHへの攻撃もしているだろう」と思い立ち、不審なアクセスを元から絶つ方法を採りました。

環境

AWS Lightsailで以下を動かしています。

  • Ubuntu 20.04
  • いわゆるLAMP環境

前提

以下が準備済みです。

  • Mod_Security導入済み
  • 前述したmod_securityから不審なアクセス元のみを抜き出したIPアドレスのリストがある
    • このリストをnegativelist.txtとして用意しています。
リスト形式
192.168.0.1
192.168.1.123

のように、一行ずつIPアドレスだけが記述されているファイルです。

さっくりとした手順

  1. ufwを有効化します。
  2. 不審なアクセス元のIPアドレスのみを抜き出したnegativelist.txtを一行ずつ読み込みアクセスを遮断するシェルスクリプトを作成します。
  3. 作成したスクリプトを実行します。

実行の前の注意事項

  • 自環境のアクセスが遮断される可能性があることに注意してください。
  • 事前にスナップショットやバックアップを取り、失敗した時に備え切り戻しができる準備を強く推奨します
  • この方法によりアクセスができなくなった等に対し、筆者は責任を負いかねます。

手順

全て管理者権限で実施しています。

ufwがインストールされていることを確認します。(導入済みの場合はスキップ)

apt list ufw
#  [インストール済み] となっていることを確認します。

ufwを有効化します。(導入済みの場合はスキップ)

ufw enable

許可するサービスを指定します。(導入済みの場合はスキップ)

ufw limit ssh
# 連続したSSHアクセスを遮断します
ufw allow http
ufw allow https
# その他の許可するサービスは必要に応じて指定してください

この段階で、以下を確認します。

  • ターミナルクライアントからSSH接続ができること
  • 既存のサービスが外部NWからアクセスできること

サービス確認

ufw status
実行例
状態: アクティブ

To                         Action      From
--                         ------      ----
22                         LIMIT       Anywhere                  
80                         ALLOW       Anywhere                  
443                        ALLOW       Anywhere                  
22 (v6)                    LIMIT       Anywhere (v6)             
80 (v6)                    ALLOW       Anywhere (v6)             
443 (v6)                   ALLOW       Anywhere (v6)             

シェルスクリプトを作成します。

vi /hoge/add_ufw.sh
スクリプト内容
#!/bin/bash

# UFWを念のため事前に有効化します
ufw enable

# ファイルに書かれたIPアドレスを一行ずつ読み込みアクセスを遮断します。
while read line; do
    ufw deny from $line
# 読み込むファイルを指定します
done < /path/to/negativelist.txt

シェルスクリプトに実行権限を与えます。

chmod +x /hoge/add_ufw.sh

シェルスクリプトを実行します。

./hoge/add_ufw.sh
# 行数によっては相当な時間がかかります

実行後の確認を行います。

ufw status
実行例(抜粋)
Anywhere                   DENY        192.168.0.1              
Anywhere                   DENY        192.168.1.111              

まとめ

これで、「Webサイトに対して不審なアクセスを行ったIPをまるごと遮断する」ことが可能になりました。相当乱暴な方法ではあることにご注意ください。

Mod_SecurityのIPアドレス調査。(IPアドレスごとのカウント)

2022年12月現在、「Mod_Securityが検知したIPアドレスネガティブリストに放り込む」は達成しました。

  • これら検知したIPはどこの国からか?
  • 日々、どのぐらいの数、不審なアクセスが来ているのか?

を把握するため、シェルスクリプトを書きました。(前回はこちらです)

やりたいこと

  1. Mod_securityが検知したエラーログからIPアドレスのみを抜き出す
  2. 検出したIPアドレスがどこの国からアクセスしたかを調査してcsvファイルに出力する
  3. 同じIPアドレスごとに件数を数え、降順で並べ替える
  4. cronで定期実行する

本項でやること

  1. 同じIPアドレスごとに件数を数え、降順で並べ替える

前提と準備

以下の環境です。

  • Ubuntu 20.04とCentOS 7以降で動作を確認しました。

前回の「エラーログからIPアドレスのみを抽出し、アクセス元の国を付与する」スクリプトが導入されていることが条件です。

スクリプト生成

参考

chatGPTの力を借りました。何度か質問を変え、動作確認しつつコマンドを足しています。

1. スクリプトを作成します。

vi ip_count.sh
スクリプト内容
#!/bin/bash

# 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

exit 

スクリプトに実行権限を付与します。

chmod +x ip_count.sh

動作確認

任意のディレクトリに以下のファイルがあることを確認します。

  • ip_check.sh スクリプトが生成したログip_list.YYYYMMDD.csv
  • ip_count.sh スクリプト

スクリプト実行

./ip_count.sh

スクリプト実行結果

出力先(上記例ではスクリプトを配置したディレクトリ)に以下のファイルが出力されます。

  • sorted_ip.YYYYMMDD.csv (以下の様に、アクセスごとの件数とIPアドレスとアクセス元の国を記述し、アクセス数の降順で並べ替えたファイル)
100, AAA.BBB.CCC.DDD,シンガポール
30, AAA.BBB.CCC.DDD,ベトナム
20,AAA.BBB.CCC.DDD,中国
  • 同時に、以下のファイルが消去されます。
  • ip.YYYYMMDD.csv (エラーログからIPアドレスのみを抜き出したファイル)
  • ip_list.YYYYMMDD.csv (IPアドレスにアクセス元を追記したファイル)
  • counted_ip.YYYYMMDD.csv (IPアドレスごとのカウントを行ったファイル)

合間に余計なファイルが含まれるので、ここはもっとスマートに書きたいです。

次にやること

  1. cronによる定期実行化
  2. redmineのプラグインredmine_logsで閲覧できるように設定

Mod_SecurityのIPアドレス調査。(アクセス元の国を抜き出す)

2022年12月現在、「Mod_Securityが検知したIPアドレスネガティブリストに放り込む」は達成しました。

  • これら検知したIPはどこの国からか?
  • 日々、どのぐらいの数、不審なアクセスが来ているのか?

を把握するため、シェルスクリプトを書きました。

やりたいこと

  1. Mod_securityが検知したエラーログからIPアドレスのみを抜き出す
  2. 検出したIPアドレスがどこの国からアクセスしたかを調査してcsvファイルに出力する
  3. 同じIPアドレスごとに件数を数え、降順で並べ替える
  4. cronで定期実行する

本項でやること

  1. Mod_securityが検知したエラーログからIPアドレスのみを抜き出す
  2. 検出したIPアドレスがどこの国からアクセスしたかを調査してcsvファイルに出力する

前提と準備

以下の環境です。

  • Ubuntu 20.04とCentOS 7以降で動作を確認しました。

nslookupコマンドが実装されていること

which nslookup
# パスがあれば実装されています。
nslookupがない場合のインストール
sudo apt-get install dnsutils

スクリプト生成

参考

以下のスクリプトをベースにしています。

https://raintrees.net/news/11

本スクリプトの作成者様と、IPアドレスと国の対応を結びつけるサービスの作成者様にこの場を借りて御礼申し上げます。

1. 国コードとアドレスを対応させたCSVを作成します。

以下のようなCSVを作成します。

vi country_list.csv
ファイル内容
AC,アセンション島
AD,アンドラ
AE,アラブ首長国連邦
AF,アフガニスタン
AG,アンティグア・バーブーダ
AI,アンギラ
AL,アルバニア
etc...

作成に当たっての参照先:

https://memorva.jp/memo/website/domain_cctld_country_code.php

スクリプトを作成します。

vi ip_check.sh
スクリプト内容
#!/bin/sh

# error.logのディレクトリを指定する場合は指定して下さい
# error.logからIPアドレスだけを抜き出して同ディレクトリのip.YYYYMMDD.csvに保存します
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がない場合にエラーを返します
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

exit

スクリプトに実行権限を付与します。

chmod +x ip_check.sh

動作確認

任意のディレクトリに以下のファイルがあることを確認します。

  • error.log (またはスクリプトにログのパスを記載)
  • ip_check.sh スクリプト
  • country_list.csv

スクリプト実行

./ip_check.sh

スクリプト実行結果

出力先(上記例ではスクリプトを配置したディレクトリ)に以下のファイルが出力されます。

  • ip.YYYYMMDD.csv (エラーログからIPアドレスのみを抜き出したファイル)
  • ip_list.YYYYMMDD.csv (以下の様に、IPアドレスとアクセス元の国を記述したファイル)
AAA.BBB.CCC.DDD,シンガポール
AAA.BBB.CCC.DDD,ベトナム
AAA.BBB.CCC.DDD,中国

次にやること

  1. このスクリプトの実行結果を元に件数ごとにまとめて並べ替えるスクリプトの作成
  2. cronによる定期実行化

mod_securityで検知したIPの自動遮断。

ここから更に改良を加えました。

やりたいこと

  • 上記抜き出したIPアドレスのリストを日々統合する。
  • 自動的にmod_securityのnegativeリストに入れる。
  • その上で普段アクセスしているIPアドレスを除外して偽陽性から逃れる。

前提

以下を導入済みです。

  • Mod_security
  • Apache 2.4.1
  • Redmine 4.2
  • ログの格納先は /var/lib/redmine/log/

手順

全て管理者権限で実施しました。

ログを格納するディレクトリを作成します。

mkdir /var/lib/redmine/log/suspicious_ip

自動実行するスクリプトを作成します。

cd /hoge/
vi negativelist_add.sh
スクリプト内容
#!/bin/sh

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

cd /var/lib/redmine/log
cat error.log | awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print  substr($0, RSTART, RLENGTH) }' | sort | uniq > /var/lib/redmine/log/suspicious_ip/suspicious_ip.`date +%Y%m%d`
chown www-data:www-data /var/lib/redmine/log/suspicious_ip/suspicious_ip.`date +%Y%m%d`
cat /var/lib/redmine/log/suspicious_ip/suspicious_ip.2* |sort |uniq > /var/lib/redmine/log/suspicious_ip_all.txt
cat suspicious_ip_all.txt > /etc/apache2/sites-available/negativelist.txt
chown www-data:www-data suspicious_ip_all.txt
sed -i  /除外したいIPアドレス/d /etc/apache2/sites-available/negativelist.txt

スクリプトに実行権限を設定します。

chmod +x negativelist_add.sh

Apacheの設定ファイルを編集します。

ここでは/etc/apache2/sites-available/redmine-le-ssl.conf にコンフィグを作成済みです。

cd /etc/apache2/sites-available
cp -pi redmine-le-ssl.conf redmine-le-ssl.conf.bak
vi redmine-le-ssl.conf
設定ファイル内容
<VirtualHost _default_:80>
servername [redmineのドメイン名]
 RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
<VirtualHost _default_:443>
servername [redmineのドメイン名]
CustomLog /var/log/redmine/access.log combined
ErrorLog /var/log/redmine/error.log
Alias /redmine /var/lib/redmine/public

# Mod Security
SecRuleEngine On
## ModSecurity有効化
SecRequestBodyInMemoryLimit 524288000
SecRequestBodyLimit 524288000
## ファイルのアップロードをできるようにします。
SecRuleRemoveById 949110
SecRuleRemoveById 941310
SecRuleRemoveById 980130
SecRuleRemoveById 911100
SecRuleRemoveById 200002
SecRuleRemoveById 200003
SecRuleRemoveById 200004
SecRuleRemoveById 959100
## 上記を無効化しないとチケット更新時にエラーとなりました(偽陽性)ため、上記ルールを除外します。
    SecRule ARGS:modsecparam "@contains test" "id:4321,deny,status:403,msg:'ModSecurity test rule has triggered'"
## テスト用の検知パラメータを付け加えます。

## Negativelist
SecRule REMOTE_ADDR "@pmFromFile negativelist.txt" "phase:1,id:2,deny,msg:'Negativelisted IP address'"

# /etc/apache2/sites-available/negativelist.txt に記載されたIPアドレスを自動的に遮断します。

<Location /redmine>
PassengerBaseURI /redmine
PassengerAppRoot /var/lib/redmine
Require all granted
<RequireAll>
    Require all granted
</RequireAll>
</Location>

  SSLEngine on
    Protocols h2 http/1.1
    Header always set Strict-Transport-Security "max-age=63072000"


SSLCertificateFile [let's encryptが指定した証明書ファイルのパス]
SSLCertificateKeyFile [let's encryptが指定した秘密鍵ファイルのパス]

#Include /etc/letsencrypt/options-ssl-apache.conf

        RewriteEngine On
        RewriteCond %{HTTP_HOST} ^samplehoge\.hogehoge
        RewriteRule ^/$ https://samplehoge.hogehoge/redmine/ [R]

</VirtualHost>

SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder     off
SSLSessionTickets       off

SSLUseStapling On
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"

設定を反映します。

apache2ctl configtest
# Syntax OKを確認します
systemctl restart apache2

crontabで自動実行できるようにします。

crontab -e

追記内容

0 8 * * * /hoge/negativelist.sh

これで、以下の動きができるようになります。

  • アクセスログ(エラーログ)に従ってIPアドレスの抜き出し
  • 重複を抜き出し、その日にアクセスされた不審なIPアドレスを記載する。
  • 蓄積されたIPアドレスを全て統合。重複を抜き出しネガティブリストに上書きする。
  • そこから普段アクセスしているIPアドレスを削除する。

Lightsail上で稼働するSnipe-ITの後処理。(含むMod_Security連携)

ローカル環境からインターネット環境へと移行した資産構成ツールSnipe-IT。これの後処理を行います。

既存の問題に対処

画像をアップロードしても、このように

“Failed to load image”と出て表示されませんでした。

https://github.com/snipe/snipe-it/issues/8701

そのものズバリのissueを発見。

.envファイルのAPP_URLを「httpから始まるドメイン」に変更してapache再起動にて治りました。

APP_URL=http://ドメイン

常時SSL化とMod_Security連携

そして、同じサーバのredmineにMod_Securityが稼働しているので、こちらも利用しない手はありません。

前提:

こちらの通り、

  • Mod_Security有効化
  • 検知したIPアドレスの抜き出ししてブロックできるようにする

処理を事前に施しています。

confファイル修正

sudo vi /etc/apache2/sites-available/snipeit-le-ssl.conf
confファイル内容
<VirtualHost _default_:80>
ServerName ドメイン名
 RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# 強制的にhttps通信に飛ばします
</VirtualHost>

<VirtualHost *:443>
    ServerName ドメイン名
    CustomLog /var/log/redmine/asset_access.log combined
    ErrorLog /var/log/redmine/asset_error.log
 # redmineのログプラグインで参照できるようにしています

# Mod Security
SecRuleEngine On
## ModSecurity有効化
SecRequestBodyInMemoryLimit 524288000
SecRequestBodyLimit 524288000
## ファイルのアップロードをできるようにします。
SecRuleRemoveById 949110
SecRuleRemoveById 941310
SecRuleRemoveById 980130
SecRuleRemoveById 911100
SecRuleRemoveById 200002
SecRuleRemoveById 200003
SecRuleRemoveById 200004
SecRuleRemoveById 959100
## 念の為、redmineで偽陽性となったフィルタをそのまま除外するようにしています
    SecRule ARGS:modsecparam "@contains test" "id:4321,deny,status:403,msg:'ModSecurity test rule has triggered'"
## テスト用の検知パラメータを付け加えます。

## Negativelist
SecRule REMOTE_ADDR "@pmFromFile negativelist.txt" "phase:1,id:2,deny,msg:'Negativelisted IP address'"
# エラーログを検知した際に検出した不審なIPアドレスを全てブロックする設定です

    DocumentRoot /var/www/html/snipe-it/public
    <Directory /var/www/html/snipe-it/public>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Require all granted
    </Directory>

  SSLEngine on
    SSLProtocol All -SSLv2 -SSLv3  -TLSv1
     SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
SSLHonorCipherOrder On 
SSLOptions +StrictRequire
Header set Strict-Transport-Security: "max-age=31536000; includeSubDomains; preload"

SSLCertificateFile /etc/letsencrypt/live/Let's Encryptで指定したドメイン/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/Let's Encryptで指定したドメイン/privkey.pem

</VirtualHost>

conf反映

sudo a2dissite snipeit.conf
# 最初に設定していたhttp通信のみのconfを無効化します
sudo apache2ctl configtest
# Syntax OKを確認します
sudo systemctl restart apache2

sudo chown www-data:www-data /var/lib/redmine/log/asset*
# redmineのログプラグインが参照できるよう、上記設定したログの所有者を変更します

これにより、常時SSL通信を行いつつ、不正アクセスの脅威をある程度守ることができます。

Mod Securityが検知したIPアドレスの抜き出し。

やりたいこと

Mod Securityを導入してから、不正アクセスがerror.logに現れるようになりました。
そのアドレスをネガティブリストに放り込むことで後続のアクセスをブロックする方法は設定しました。

そこで、

  • 日ごとにerror.logで検知したログを確認し
  • IPアドレスのみを抜き出してリスト化する

設定を行います。

環境

  • Ubuntu 20.04(Linux Mint)
  • Apache 2.4
  • Mod Security

※ログは/var/lib/redmine/log に格納されています。

手順

一般ユーザで実施します。

参考:

https://linux.just4fun.biz/?%E9%80%86%E5%BC%95%E3%81%8DUNIX%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89/%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8B%E3%82%89IP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%AE%E3%81%BF%E6%8A%BD%E5%87%BA%E3%81%99%E3%82%8B

apacheのerror.logからIPアドレスを抜き出します。

cd /var/lib/redmine/log
cat error.log | awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print  substr($0, RSTART, RLENGTH) }'
# IPアドレスのみ表示されることを確認。

IPアドレスを並べ替え、重複を除外します。

cd /var/lib/redmine/log
cat error.log | awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print  substr($0, RSTART, RLENGTH) }' | sort | uniq
# 一意のアドレスのみが表示されることを確認。

自動実行するスクリプトを作成します。

cd /hoge/
vi negativelist.sh
スクリプト内容
#!/bin/sh

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

cd /var/lib/redmine/log
cat error.log | awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print  substr($0, RSTART, RLENGTH) }' | sort | uniq > /var/lib/redmine/log/suspicious_ip.`date +%Y%m%d`

スクリプトに実行権限を付与します。

chmod +x negativelist.sh

日ごとに実行されるように設定します。

sudo su -
crontab -u www-data -e
# redmineのログプラグインで閲覧できるよう、apache実行ユーザのcronを編集します
cron内容
0 8 * * * /hoge/negativelist.sh

これで、「Mod Securityが不正アクセスと見なしたIPアドレスを日ごとに抜き出す」仕組みが整いました。

(シェルスクリプトで指定したディレクトリ内に、suspicious_ip.yyyymmdd というファイルが作成されます。
 また、/var/lib/redmine/log 配下に置くことで、redmineのログプラグインで表示することができます。)

直接ネガティブリストに追記しないのは、偽陽性で自分自身がブロックされるのを防ぐためです。

Page 1 of 2

Powered by WordPress & Theme by Anders Norén