DDoS攻撃への迅速な対応

私が面倒を見るリソースの1つは、良いユーザーと悪いユーザーの両方に突然予想外に人気が出ました。 強力な、一般的に、鉄は負荷に対処することをやめました。 サーバー上のソフトウェアは最も一般的です-Linux、Nginx、PHP-FPM(+ APC)、MySQL、バージョンは最新です。 サイトはDrupalとphpBBをスピンします。 ソフトウェアレベルでの最適化(memcached、不足しているデータベース内のインデックス)は少し役立ちましたが、根本的には問題を解決しませんでした。 そして問題は、静的、動的、特にベースに対する多数のクエリです。 Nginxで次の制限を設定します。



接続時

limit_conn_zone $binary_remote_addr zone=perip:10m; limit_conn perip 100;
      
      





およびダイナミクスのリクエストの速度(php-fpmのfastcgi_pass)

 limit_req_zone $binary_remote_addr zone=dynamic:10m rate=2r/s; limit_req zone=dynamic burst=10 nodelay;
      
      





ログによると、誰も最初のゾーンに入らないが、2番目のゾーンがそれを完全に満たすことは明らかであるということです。



しかし、悪者たちはつまづき続けたので、私は彼らを以前に-ファイアウォールレベルで、長い間ドロップしたかったのです。



最初に彼は自分でログを解析し、特に迷惑なログをiptables経由で浴場に追加しました。 その後、小包はすでに5分ごとに王冠上にあります。 fail2banを試しました。 多くの悪者がいることに気付いたとき、それらをipset ip hashに転送しました。



ほとんどすべてがうまくいきましたが、不快な瞬間があります:

-ログの解析/ソートもまともな(プロセッサ)時間を要します

-隣接する分解(ログ)間で新しい波が始まった場合、サーバーはバカです。



ブラックリストに違反者をすばやく追加する方法を見つける必要がありました。 最初は、モジュールをNginx + ipsetsを更新するデーモンに記述/追加するというアイデアがありました。 デーモンがなくても可能ですが、ルートからNginxを実行する必要がありますが、これは美しくありません。 書くのは本物ですが、あまり時間がないことに気付きました。 私は似たようなものを見つけませんでした(たぶん見栄えが悪いのでしょうか?)、そしてそのようなアルゴリズムを思いつきました。



制限を超えると、Nginxは503rd Service Temporarily Unavailableエラーをスローします。 だから私はそれに夢中にすることにしました!



各場所について、エラーのある独自のページを作成します

 error_page 503 =429 @blacklist;
      
      





そして、対応する名前の場所

 location @blacklist { fastcgi_pass localhost:1234; fastcgi_param SCRIPT_FILENAME /data/web/cgi/blacklist.sh; include fastcgi_params; }
      
      





もっと面白い。

CGIスクリプトのサポートが必要です。 spawn-fcgiおよびfcgiwrapをインストール、構成、実行します。 私はすでに収集の準備ができていました。



CGIスクリプト自体

 #!/bin/bash BAN_TIME=5 DB_NAME="web_black_list" SQLITE_DB="/data/web/cgi/${DB_NAME}.sqlite3" CREATE_TABLE_SQL="\ CREATE TABLE $DB_NAME (\ ip varchar(16) NOT NULL PRIMARY KEY,\ added DATETIME NOT NULL DEFAULT (DATETIME()),\ updated DATETIME NOT NULL DEFAULT (DATETIME()),\ counter INTEGER NOT NULL DEFAULT 0 )" ADD_ENTRY_SQL="INSERT OR IGNORE INTO $DB_NAME (ip) VALUES (\"$REMOTE_ADDR\")" UPD_ENTRY_SQL="UPDATE $DB_NAME SET updated=DATETIME(), counter=(counter+1) WHERE ip=\"$REMOTE_ADDR\"" SQLITE_CMD="/usr/bin/sqlite3 $SQLITE_DB" IPSET_CMD="/usr/sbin/ipset" $IPSET_CMD add $DB_NAME $REMOTE_ADDR > /dev/null 2>&1 if [ ! -f $SQLITE_DB ]; then $SQLITE_CMD "$CREATE_TABLE_SQL" fi $SQLITE_CMD "$ADD_ENTRY_SQL" $SQLITE_CMD "$UPD_ENTRY_SQL" echo "Content-type: text/html" echo "" echo "<html>" echo "<head><title>429 Too Many Requests</title></head>" echo "<body bgcolor=\"white\">" echo "<center><h1>429 Too Many Requests</h1></center>" echo "<center><small><p>Your address ($REMOTE_ADDR) is blacklisted for $BAN_TIME minutes</p></small></center>" echo "<hr><center>$SERVER_SOFTWARE</center>" echo "</body>" echo "</html>"
      
      





実際、おそらくSQLiteを除き、すべてが明らかです。 これまで統計のためだけに追加しましたが、原則として、ブラックリストから古いバディを削除するために使用できます。 5分の時間も使用されません。



ブラックリストは次のように作成されました

 ipset create web_black_list hash:ip
      
      





各iptablesルールは、構成と想像力に応じて、独自のルールを持つことができます。



あるホスティング事業者で、管理されたファイアウォールのサービスを見ました。 ipset addスクリプトの小さなcurlセッションを置き換えると、チャネルとネットワークインターフェイスをアンロードすることにより、外部ファイアウォールで不良セッションをフィルタリングできます。



ZY:フォーラムの1人の「ハッカー」のメッセージは、彼がどれほど早くサーバーを停止させたかに微笑んでいました。 彼はサーバーが彼に何を置いたのか見当がつかなかった。



追加:

ブラックリストを作成する際にタイムアウトパラメータを使用する際のアドバイスをくれた同志megazubrに感謝します-cronでクリーンアップする必要はありません。 これで、タイムアウトを5分間で作成するコマンドは次のようになります。
 ipset create web_black_list hash:ip timeout 300
      
      





また、安全上の懸念を指摘してくれたalexkbsにも感謝します。 実稼働サーバーでは、fastcgiハンドラーは、nginxのみの許可を持つUNIXソケットでハングアップする必要があります。 私たちが書いた設定では:
 error_page 503 =429 @blacklist; location @blacklist { fastcgi_pass unix:/var/run/blacklist-wrap.sock-1; fastcgi_param SCRIPT_FILENAME /data/web/cgi/blacklist.sh; include fastcgi_params; }
      
      



spawn-fcgi.wrapの場合:
 FCGI_SOCKET=/var/run/blacklist-wrap.sock FCGI_PROGRAM=/usr/sbin/fcgiwrap FCGI_EXTRA_OPTIONS="-M 0700 -U nginx -G nginx"
      
      






All Articles