11

Linux で実行されている、標準のネットワーク ソケット経由で TCP/IP を使用する C++ で記述された Web アプリがあります。このサービスは、ワイルドで毛むくじゃらのインターネットに開かれています。

自動化されたスクリプトを実行しているスパマーから、定期的に大量の悪質なリクエストを受け取ります。これらを検出してソケットを閉じることができます。現在、完了した有効なリクエストに対して行うのと同じように、ソケット lib を次のように閉じて、丁寧なソケット クローズを行います。

close( mSocket );

しかし、通常、ソケットを閉じると、ソケット接続が終了したことがスパム スクリプトに通知され、すぐに別の不正な要求が開始されることがあります。

システムの開いているソケットをクリーンアップする TCP/IP 接続を終了する最善の方法は何ですか? つまり、私にとってはコストが最も低く、コストが最も高い方法でソケットを閉じたいということです。

@ニコラス・ウィルソン:

TCP_REPAIR を使用するのは良い考えのようです。TCP_REPAIR モードでソケットが閉じられると、FIN または RST パケットは送信されません。リモートソケットはぶら下がったままです。試してみて、また報告します。ここに私の(テストされていない)コードがあります:

if ( abuse )
{
   int aux = 1;
   if ( setsockopt( mSocket, SOL_TCP, TCP_REPAIR, &aux, sizeof( aux )) < 0 )
      reportError( "Tried to do a rude socket close... but could not turn on repair mode.\n" );
}
close( mSocket );

これが機能するかどうかはまた報告します。(@edit: 以下のテスト済みの回答)

@ 「ソケットを開いたままにする」という考え:

これは機能しますが、最適ではありません。攻撃者は、開いているソケットでシステムを飽和させることができます。要求ごとに、開いたままの新しいソケットが作成されます。DOS 攻撃では、最終的にソケットが不足します。

次に、開いているソケットの管理にも問題があります。

  1. 閉じないでください。開いているソケットは永久に残ります。攻撃者のコスト: 高い - フィンは得られません。私にとってのコスト:より高い。すべてのファイル記述子は最終的に使用されます。
  2. ソケットごとにスレッドを生成して 10 分間スリープさせてから、ソケットを閉じます。攻撃者のコスト: 高い - フィンは得られません。私にとってのコスト:より高い。私は最終的にソケットを閉じますが、リクエストごとに、攻撃者よりも長くソケットを使い果たし、スレッドのオーバーヘッドがあります。
  3. 乱用されたすべてのソケットの期限切れを処理するスレッドを生成します。攻撃者のコスト: 高い - フィンは得られません。私にとってのコスト:より高い。2のように、たくさんのソケットが開いたままです。それを管理するための単一スレッドのオーバーヘッド。コードの複雑さ、煩わしさ。
4

4 に答える 4

4

OK、いくつかの調査を行いました。TCP_REPAIRに基づいて、私に役立つ答えがあります。最初に思ったよりも少し複雑です。

if ( abuse )
{
   // read some bytes from the spammer - to establish the connection
   u32 tries = 20;
   while ( tries )
   {
      sleep( 1000 );
      char tmpBuf[32];
      s32 readCount = recv( mSocket, &tmpBuf[0], 32, 0 );
      if ( readCount > -1 ) break;
      tries--;
   }
#ifdef TCP_REPAIR
   int aux = 1;
   if ( setsockopt( mSocket, SOL_TCP, TCP_REPAIR, &aux, sizeof( aux )) < 0 )
   {
     reportError( "could not turn on repair mode" );
   }
#else // !TCP_REPAIR
   // no TCP REPAIR - best we can do is an abort close
   struct linger so_linger;
   so_linger.l_onoff = 1;
   so_linger.l_linger = 0;
   if ( setsockopt( mSocket, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger ) < 0  )
   {
      reportError( "Cannot turn off SO_LINGER" );
   }
#endif // TCP_REPAIR
}
close( mSocket );

カーネルレベルでは、接続を閉じると(closeまたはshutdownのいずれかを使用して)、TCPスタックはFINまたはRSTパケットを送信します。いずれにせよ、攻撃者はあなたが接続を閉じたことを通知されます。

私たちは静かに接続を閉じて、あなたが答えていないことに気付くまで彼らを待たせたいと思っています...私たちは説得力があるからです。

TCP_REPAIRは、ソケットを「フリーズ」し、その状態を保存し、別のプロセスまたは別のシステムでソケットの状態を再ロードできるように設計された新しいソケットAPIです。通常の使用では、クライアントは接続が他の場所に転送されたことを知ることはありません。

ただし、このAPIを悪用することはできます。ソケットを修復モードにしますが、その状態を保存したり、復元したりすることはありません。修復モードでソケットを閉じると、サイレントに削除されます。

これは、すでに開始されている不正なリクエストに対して機能します。つまり、スパマーの要求を読み、それが詐欺であると判断し、TCP_REPAIRがそれを殺したということです。

ただし、接続直後に、最初にソケットを読み取らずにIPで要求をブロックすると、どういうわけかリモートパーティに通知されます。彼らはRSTを取得します。または、接続内の何かが完全に完了することはなく、リモートシステムがほとんどすぐに要求を中止する可能性があります。

したがって、最初にハッカーのソケットから数バイトを読み取ります。私の場合、ソケットはすでに非ブロッキングモードになっています。しかし、そうでない場合は、ソケットを非ブロックに設定するか、ハッカーが接続を開くことを許可しますが、パケットを送信せず、サーバーをハングさせたままにします-あなたが彼に行う予定のように。数マイクロ秒経ってもパケットが届かない場合は、とにかく彼をシャットダウンします。

しかし、あなたが彼から数バイトを読んだ場合、彼のプログラムは決して来ないあなたからの応答を待ったままになります。

TCP_REPAIRは、Linuxカーネル3.5以降でのみ使用できます。その下で私ができる最善のことは、「ダーティ」なソケットを閉じることです。これは、彼にFINを送信する代わりに、彼とRSTを送信する場所です。有効な接続が確立されなかったように見えます。これを行うには、SO_LINGERをオフにして、基本的にソケット接続を切断し、ハンドシェイクを閉じてから、closeを呼び出します。

魅力のように機能します。ブラウザをここに向けてください。

http://oroboro.com/fail

Chromeは少なくとも5〜10秒間そこにハングします。私が毎秒10ヒットを取得していた私のログを見ると、彼は10秒ごとにしか私をヒットできません。これから私のシステムにロードします:0。

じゃあね!

于 2013-01-04T21:10:04.293 に答える
3

悪意のあるクライアントを検出した場合は、接続を閉じるだけでなく、同じIPアドレスから発信された新しい接続も拒否することをお勧めします。

少なくともできることは、アプリケーションのIPをブラックリストに登録することです。禁止されているIPアドレスのリストを保持し、そのリストにあるIPから発信された受け入れ済みのソケットをすぐに閉じます。

ただし、より多くのリソースを保護するには、ネットワークアーキテクチャのさらに外側の接続をブロックすることをお勧めします。可能になったら、ゲートウェイルーターにブロックするように通知します。それが不可能な場合は、ロードバランサーにブロックさせてみてください。それができない場合は、少なくともサーバーのローカルファイアウォールにルールを追加してください。

ただし、このような攻撃の多くは、消費者向けのインターネット接続(ユーザーの意識の有無にかかわらず)から発生することに注意してください。これは通常、IPアドレスが割り当てられ、定期的に動的に再割り当てされることを意味します。数日前にスパマーによって使用されていたIPが、正当なユーザーによって使用される可能性があります。したがって、IPベースの禁止は永遠に続くべきではありません。

于 2013-01-04T14:32:33.703 に答える
1

これを使って:

#include <sys/socket.h>

int shutdown(int socket, int how);

を送信しRST、すぐに閉じます(接続)。これにより、そのポートにはサービスがないように見え、攻撃者はそのポートでのスパムをやめることができれば幸いです。close()ハンドルを解放するために呼び出します。

于 2013-01-04T14:34:50.860 に答える
0

を検出すると、abuse

abuseソケットの1 つを使用して「スパマー」をポットに入れたことを検出したときはいつでも、「スパマー」用のソケットのプールを用意してください。空いているソケットが利用できない場合は、最も古いものをリサイクルし、シャットダウンして閉じます。

接続!abuseが適切なソケットを使用できるようになっている場合。

于 2013-01-04T18:10:54.210 に答える