自宅サーバのセキュリティを考える3

自宅サーバー

sslhdへのログイン試行ログを見つけてから、セキュリティ対策について検討してきました。

攻撃者はターゲットを絞るとサーバに対してブルートフォース(総当たり)攻撃でセキュリティを突破しようとしてきます。

もちろん、サーバへの侵入は許さないのですが、ログイン試行を許してしまうとCPU負荷が高くなるという悪影響があります。

そこでFW(iptables)によるアクセス拒否を考えたのですが、攻撃者のIPアドレスは固定ではなく、対策したところでIPアドレスを変えて攻撃してきます。

そのため、外部からのアクセスに対するセキュリティを少しでも高める為に、以下のようにFWを更新する仕組みを考えました。

今回、sshログイン失敗履歴から攻撃者のIPアドレスを特定し、FW(iptables)に自動でアクセス拒否ルールを設定するシェルスクリプトを作成してみましたので、記事にしたいと思います。

やりたいこと

復習になりますが、以下のような自律的にFW(iptables)を更新する仕組みを作りたいと考えています。

この仕組みを実現するためのシェルスクリプトについて検討しました。

スクリプトの概要

今回は、攻撃者と思われるIPアドレスを拒否(ブロック)するスクリプトを作成しました。

以下のようなことを実現するスクリプトです。

スクリプトで実現すること
  1. sshのログイン失敗履歴(/var/log/auth.log)の中から、ログインに失敗した接続元IPアドレスからのアクセスを拒否する。
  2. 自分が指定するIPアドレスからのアクセスを拒否する。
  3. 自分が指定するIPアドレスからのアクセスは拒否しない。
  4. iptablesには、拒否するIPアドレスのみを設定する。

1はsshのログイン失敗履歴(/var/log/auth.log)から、ログインに失敗したIPアドレスを攻撃者とみなし、アクセスを拒否(プロック)します。

攻撃者のIPアドレスはログの“Failed”あるいは“Invalid”を含む行のIPアドレスとします。

2は、あらかじめ指定した拒否したいIPアドレスを対象に、アクセス拒否します。

1と2の違いは、1はsshのログイン失敗履歴から抽出するIPアドレスが対象なのに対し、2はログに関わらず静的なIPアドレスを対象にする点です。

「ログにはないけど、このIPアドレスからのアクセスは拒否したい」、という場合を想定しています。

3は、間違って自身の信頼されたネットワークからのアクセスを拒否しないようにするためです。

自分が自宅サーバにsshログインする際に、うっかりパスワード入力を間違ってしまうとログイン失敗履歴に残ってしまうので、その場合でもアクセス拒否しないよう指定したIPアドレスからのアクセスは拒否しないようにします。

4は、FWの設定の仕方です。

今回は、アクセス拒否するIPアドレスを対象にFWを設定します。

INPUTポリシへの追加のためFWは「デフォルト許可」を前提として、拒否するIPアドレスのみを明にiptalbesにルール追加します。

ベン図

一旦、整理するとやりたいことを以下のIPアドレスの集合で表してみます。

「拒否したいIPアドレス」は、スクリプトで実現することの1,2に相当します(A,D,F,G)。

また、「拒否したIPアドレス」は、 拒否したいIPアドレスとは似て非なるもので既にiptablesにルール(拒否)が設定されているIPアドレスの集合です(B,D,E,G)。

拒否したいIPアドレスの中には、これからルールに登録しなければならないIPアドレス(A,F)と既にiptablesに登録されているもの(D,G)があります。

iptablesへの二重登録を避けるために、後者についてはルールを追加してはいけないのでこのように分類して考えます。

最終的なFW(iptables)の設定内容は、拒否するIPアドレスの追加ルール設定(A)と、許可するIPアドレスの既存ルール削除設定(E,G)となります。

拒否したいIPアドレスと許可したいIPアドレスが重複する場合、そのIPアドレスは許可することとします。

また、拒否したIPアドレス(iptables設定済み)と許可したいIPアドレスが重複する場合も同様に、そのiPアドレスは許可(iptablesから削除)することとします。

上記の、A,G,Eのiptablesルールを作成するシェルスクリプトを作成しました。

※図中の「許可したいIPアドレス」「許可するIPアドレス」は、正確には「拒否したくないIPアドレス」「拒否しないIPアドレス」と書くのが正しいです。

作成したシェルスクリプト

シェルスクリプト(bash)を書いてみました。

このシェルスクリプトによって書き換えたルールは後で元に戻すことができるので、興味があればお試しで実行してみてください。

コメントと空行を除けば、53行のスクリプトです。

Debian系のLinux(Ubuntu、Raspbian)を想定していますので、RedHat系のLinux(CentOS)で実行する場合はログの場所(91行目)のパスを/var/log/secureに修正してください。

スクリプトの処理について、以下の記事で解説します。

使い方

事前準備

上記のシェルスクリプトを適当な場所(/path/to/script/)において、実行権限を付与してください(必須)。

事前に拒否したいIPアドレスリスト許可したいIPアドレスリストを作成しておきます(任意)。

(IPアドレスと許可したいIPアドレスが無ければ、シェルスクリプト単体で動作します。)

ここでは、シェルスクリプトと同ディレクトリ配下にdeny-ip.dディレクトリを作成し、ファイルを配置します。

ローカルIPアドレスは拒否されないようにしていますので、ローカルIPアドレスはallow_ip_listに記載は不要です。

事前に必要なファイルの構成は以下となります。

FWの更新(update)

firewall(iptables)を更新するときは、以下のコマンドを実行します。

初回起動時は、以下のような出力となります。

deny-ip.dが無い場合は、シェルスクリプトと同ディレクトリ配下に、deny-ip.dディレクトリとファイルが作成されます。

iptablesに追加したルールを見たい場合は、iptables-shを参照してください。

FWを元に戻す(remove)

このシェルスクリプトによって追加されたルールを消します。

iptablesが元通りになります。

iptablesルール確認(status)

このシェルスクリプトによって追加されたルールを参照します。

iptables(DENY-IP)のルールが表示されます。

拒否したIPアドレスリストを書き出す(dump)

iptablesにルール追加されたIPアドレスリストをdeny_ip_listに書き出し、静的な拒否IPアドレスリストを作成します。

dumpすることによって、ログ(/var/log/auth.log)に記録されていなくても、アクセス拒否ルールを追加することができます。

iptables(DENY-IP)のルールからIPアドレスを抽出してdeny_ip_listに出力します。

定期実行

一通り動作確認をしてみて、問題なかったのでこれをcrontabに設定して自動的に起動させてみます。

以下の内容を追記します。

追記の意味は、

  • システムブート時にdeny-ip updateを実行する
  • 毎日朝4:55にdeny-ip updateを実行する
  • 毎週月曜日0:00にdeny-ip stausを実行して、deny-ip dumpを実行する

毎週deny-ip stausを実行するのは、実行結果をログに残すためです。

これで、毎日自動的にFWを更新する仕組みができました!

1週間運用してみて

1週間運用してみて、効果があったのか確認してます。

結果は0件、良好です。

ただ、たまたまアクセスが無かっただけかもしれないのでフィルタしたパケット数を確認してみます。

DENY-IPが42M(3323MB)のパケットをブロックしているようです。

ちゃんと機能しています!

まとめ

sshログイン失敗履歴から攻撃者のIPアドレスを特定し、FW(iptables)に自動でアクセス拒否ルールを設定するシェルスクリプトを作成してみました。

これをcrontabで自動起動させてやれば、攻撃者から身を守れます。

そして、私の自宅サーバでも絶賛稼働中です。

そのため、間違っても私のサーバ(komone-life.com)にsshでログインしようとしないでください。

sshログインに失敗すると、攻撃者とみなして翌日にはそのIPアドレスからのアクセスが拒否されてこのブログが読めなくなってしまいます。

ブログにアクセスできなくなった方は、フィルタを解除しますのでどうにかして私に連絡してください。

ふつうの人が私の自宅サーバにsshでログインしてくることは無いので、このスキーム(sshログイン失敗したIPアドレスをブロックする)に問題はないはず。

そして、このプログラムを作りながら思ったことがあります。

それは、、

結局22番ポート空けるならFail2Banでよくね?

うん、、だけど、良い頭の体操になったからいいんです。

参考になれば幸いです。

コメント

タイトルとURLをコピーしました