66

序章

IP addressWeb アプリケーション/サーバーから多数をブロックするにはどうすればよいですか。PHP明らかに、それはまたは任意のプログラミング言語で簡単に実行できます

$ipList = []; // array list or from database
if (in_array(getIP(), $ipList)) {
    // Log IP & Access information
    header("https://www.google.com.ng/search?q=fool"); // redirect
    exit(); // exit
} 

または使用してhtaccess

order allow,deny
deny from 123.45.6.7
deny from 012.34.5.
# .... the list continues
allow from all

問題

  • 全体をブロックしようとして100k plus individual IPsいますsubnets
  • そのようなIPをブロックする前に、ユーザーがPHPにアクセスするのを避けようとしています
  • 100000+ は 1.5MB を超えており、htaccess常に情報をロードする場合は大量です。
  • IP のデータベースはまだ拡大中です ... さらに値を動的に追加する必要があります
  • 100000以上の禁止を設定するiptablesのはばかげています(間違っているかもしれません)

愚かな考え

order allow,deny
deny from database    <-------- Not sure if this is possible
allow from all

質問

  • htaccessデータベース (Redis、Crunchbase、Mongo、MySQL、または Sqlite) からリストを取得することは可能ですか?
  • 本番環境でこの種の問題を管理するための目に見える解決策はありますか
  • 最善の解決策はBlock the IPs at the firewall level、ファイアウォールに IP を実際に追加/削除する方法があることです。

ついに

私のアプローチは完全に間違っているかもしれません...スパマーやボットネットが増加しているため、私が望むのは目に見える解決策だけです...

これはDOS単純な攻撃とは関係ありません...get lost response

アップデート

  • ファイアウォール: Cisco PIX 515UR
4

11 に答える 11

67

ブロックしたい IP アドレスのリストをテキスト ファイルに保存するか、それをdbm ハッシュ ファイルに変換してから、mod_rewrite のRewriteMap. サーバー/仮想ホスト構成でこれを設定する必要があります。htaccess ファイルでマップを初期化することはできません

RewriteEngine On
RewriteMap deny_ips txt:/path/to/deny_ips.txt

RewriteCond ${deny_ips:%{REMOTE_ADDR}|0} !=0
RewriteRule ^ - [L,F]

/path/to/deny_ips.txtファイルは次のようになります。

12.34.56.78 1
11.22.33.44 1
etc.

基本的に、拒否する IP とスペースの後に「1」を入力します。このテキスト ファイルに IP があると、サーバーは403 Forbiddenを返します。少しスピードアップするには、 を使用しhttxt2dbmて dbm ハッシュを生成し、次のようにマッピングを定義します。

RewriteMap deny_ips dbm:/path/to/deny_ips.dbm

多くの IP でこのような mod_rewrite を使用した場合のパフォーマンス ヒットはわかりませんが、Linux で 3Ghz i686 で実行されている apache 2.2 での簡単なベンチマーク テストでは、リスト内の 5 つの IP と 102418 の差はごくわずかです。abの出力によると、それらはほぼ同一です。


特定の質問への対処:

htaccess がデータベース (Redis、Crunchbase、Mongo、MySQL、または Sqlite) からリストを取得することは可能ですか?

書き換えマップを使用すると、「prg」マップ タイプを使用して、マッピング タイプの外部プログラムを実行できます。その後、perl、php などのスクリプトを記述して、データベースと通信して IP アドレスを調べることができます。また、「注意」に記載されている注意事項にも注意してください。次に、このマップを他のマップと同じように使用します ( RewriteCond ${deny_ips:%{REMOTE_ADDR}|0} !=0)。これにより、基本的にすべてのリクエストのボトルネックが発生します。データベースと対話するための最適なソリューションではありません。

ただし、Apache 2.4 にはdbd/fastdbdマップ タイプがあり、 mod_dbdを介してクエリを作成できます。これははるかに優れたオプションであり、mod_dbd モジュールはデータベースへの接続、プール接続などを管理します。したがって、マップ定義は次のようになります。

RewriteMap deny_ips "fastdbd:SELECT active FROM deny_ips WHERE source = %s"

" source " (IP アドレス) と " active " (アクティブの場合は 1、非アクティブの場合は 0 ) の2 つの列を持つテーブル " deny_ips " があると仮定します。

本番環境でこの種の問題を管理するための目に見える解決策はありますか

ブロックされたすべての IP をデータベースに保存している場合は、データベース テーブルの内容を管理する必要があります。dbm マップ タイプを使用している場合、少なくともperl にはdbm ファイルを管理するための DBI があることがわかっているので、それを使用して IP エントリを拒否リストに追加/削除できます。これまで使ったことがないので、あまり詳しくは言えません。フラットなテキスト ファイルの管理は、特にエントリに追加するだけでなく、エントリを削除する予定がある場合は、非常に複雑になります。データベースと apache 2.4 の mod_dbd を使用することを除けば、これらのソリューションのいずれも、すぐに使用できるものや生産準備が整っているとは思いません。カスタム作業が必要になります。

最善の解決策は、ファイアウォール レベルで IP をブロックすることです。実際にファイアウォールに IP を追加/削除する方法はありますか

IPtables には、ベータ版としてマークされたperl インターフェイスがありますが、私はこれまで使用したことがありません。libiptcがありますが、 netfilter の faqによると:

ルールを追加/削除するための C/C++ API はありますか?

残念ながら、答えは「いいえ」です。

「でも、libiptc はどうするの?」と思うかもしれません。メーリングリストで何度も指摘されているように、libiptc は公開インターフェースとして使用されることを意図したものではありませんでした。安定したインターフェースを保証するものではなく、Linux パケット フィルタリングの次のバージョンで削除する予定です。とにかく、libiptc はあまりにも低層であり、合理的に使用することはできません。

このような API には根本的な不足があることを十分に認識しており、その状況を改善するために取り組んでいます。それまでは、system() を使用するか、パイプを iptables-restore の stdin に開くことをお勧めします。後者は、パフォーマンスを大幅に向上させます。

したがって、API の安定性がなければ、libiptc ソリューションがどれほど実行可能かはわかりません。

于 2013-03-22T22:19:46.480 に答える
34

別の視点

こんにちは。それぞれ 8KB の長さの 2 つのデータ チャンクで 2 バイトにアクセスすることで、アドレスがブロックされているかどうかを確認できます。はい、私は本気です...説明するのに少し時間がかかるので、しばらくお待ちください。

法則

IP アドレスはアドレスであり、実際には 4 バイトの数値です。

問題は、ビット位置をアドレス指定するようにするとどうなるかということです。

答え: わかりました。

  2^32 = 4 Giga Bits 

アドレッシングスペースの

 4Gb/8 = 512 Mega Bytes

割り当ての。痛い!しかし、心配しないでください。ipverse のすべてをブロックするつもりはありません。512MB は誇張です。

これにより、解決への道が開けます。

小人事件

0 から 65535 までの IP アドレスしか存在しないリリプティアンの世界を考えてみてください。したがって、アドレスは 0.1 または 42.42 から 255.255 までのようなものです。

現在、この世界の王様は、いくつかの L-IP (liliput ip) アドレスをブロックしたいと考えています。

最初に、256 * 256 ビット長の仮想 2D ビット マップを作成します。

 64 K Bits = 8 K Bytes.

彼は、自分が国王であるため嫌いな厄介な「革命」サイトをブロックすることにしました。たとえば、アドレスは 56.28 です。

Address     = (56 * 256) + 28  = 14364.(bit position in whole map)
Byte in map = floor(14364 / 8) =  1795.
Bit position= 14364 % 8        =     4.(modulus)

彼はマップ ファイルを開き、1795 番目のバイトにアクセスしてビット 4 を設定し (| 16 で)、それを書き戻して、サイトがブロックされていることを示します。

彼のスクリプトは 56.28 を検出すると、同じ計算を実行してビットを調べ、設定されている場合はアドレスをブロックします。

さて、物語の教訓は何ですか?さて、このリリプティアン構造を使用できます。

練習

実世界のケース

512MB のファイルを割り当てることは適切な選択ではないため、「必要なときに使用する」というアプローチでリリプティアンのケースを現実の世界に適用できます。

次のようなエントリを持つ BLOCKS という名前のデータベース テーブルを考えてみてください。

IpHead(key): unsigned 16 bit integer,
Map        : 8KB BLOB(fixed size),
EntryCount : unsigned 16 bit integer.

そして、BASE という名前の下の構造を持つエントリが 1 つだけの別のテーブル

Map        : 8KB BLOB(fixed size).

ここで、受信アドレスが 56.28.10.2 であるとします。

スクリプトは BASE テーブルにアクセスし、マップを取得します。

上位のIP 番号 56.28を検索します。

Address     = (56 * 256) + 28  = 14364.(bit position in whole map)
Byte in map = floor(14364 / 8) =  1795.
Bit position= 14364 % 8        =     4.(modulus)

マップのバイト 1795 ビット 4 を調べます。

ビットが設定されていない場合、それ以上の操作は必要ありません。つまり、範囲 56.28.0.0 から 56.28.255.255 にブロックされた IP アドレスはありません。

ビットが設定されている場合、スクリプトは BLOCKS テーブルにアクセスします。

上位の IP 番号は 56.28 で、これは 14364 であるため、スクリプトはインデックス IpHead = 14364 で BLOCKS テーブルをクエリします。レコードを取得します。BASE でマークされているため、レコードが存在する必要があります。

スクリプトは下位IP アドレスの計算を行います

Address     = (10 * 256) + 2   = 2562.(bit position in whole map)
Byte in map = floor(2562 / 8) =   320.
Bit position= 2562 % 8        =     2.(modulus)

次に、フィールド Map のバイト 320 のビット 2 を見て、アドレスがブロックされているかどうかを確認します。

仕事終わり!

Q1:なぜ BASE を使用するのですか? 14364 で BLOCKS を直接クエリできます。

A1:はい、可能ですが、データベース サーバーの BTREE 検索よりも BASE マップ検索の方が高速です。

Q2: BLOCKS テーブルの EntryCount フィールドは何のためにありますか?

A2:同じレコードのマップ フィールドでブロックされた IP アドレスの数です。したがって、IP のブロックを解除して EntryCount が 0 に達すると、その BLOCKS レコードは不要になります。これは消去でき、BASE マップの対応するビットは設定解除されます。

IMHOこのアプローチは非常に高速です。また、ブロブの割り当ては、レコードごとに 8K です。db サーバーはブロブを個別のファイルに保持するため、4K、8K、または 4K の倍数のページングを持つファイル システムは高速に反応します。

ブロックされたアドレスが分散している場合

これは、データベースの BLOCKS テーブルが不必要に大きくなる懸念事項です。

しかし、そのような場合の代替手段は、2097152 バイト = 2MB に相当する 16777216 ビット長の 256*256*256 ビット キューブを使用することです。

前の例では、Higher Ip 解決は次のとおりです。

(56 * 65536)+(28 * 256)+10      

したがって、BASE は db テーブル レコードの代わりに 2MB のファイルになり、開かれ (fopen など)、シークによってビットがアドレス指定されます (fseek のように、ファイルの内容全体を読み取ることはありません。不要です)。次に、以下の構造を持つ BLOCKS テーブルにアクセスします。 :

IpHead(key): unsigned 32 bit integer, (only 24 bit is used)
Map        : 32 unsigned 8 bit integers(char maybe),(256 bit fixed)
EntryCount : unsigned 8 bit integer. 

これは、bitplane-bitplane (8K 8K) バージョンのブロック チェックの php サンプル コードです。

補足: このスクリプトは、いくつかの呼び出しを削除するなどして、さらに最適化することができます。ただし、理解しやすいように、このように記述します。

<?
define('BLOCK_ON_ERROR', true); // WARNING if true errors block everyone

$shost = 'hosturl';
$suser = 'username';
$spass = 'password';
$sdbip = 'database';
$slink = null;

$slink = mysqli_connect($shost, $suser, $spass, $sdbip);
if (! $slink) {
    $blocked = BLOCK_ON_ERROR;
} else {
    $blocked = isBlocked();
    mysqli_close($slink); // clean, tidy...
}

if ($blocked) {
    // do what ever you want when blocked
} else {
    // do what ever you want when not blocked
}
exit(0);

function getUserIp() {
    $st = array(
            'HTTP_CLIENT_IP',
            'REMOTE_ADDR',
            'HTTP_X_FORWARDED_FOR'
    );
    foreach ( $st as $v )
        if (! empty($_SERVER[$v]))
            return ($_SERVER[$v]);
    return ("");
}

function ipToArray($ip) {
    $ip = explode('.', $ip);
    foreach ( $ip as $k => $v )
        $ip[$k] = intval($v);
    return ($ip);
}

function calculateBitPos($IpH, $IpL) {
    $BitAdr = ($IpH * 256) + $IpL;
    $BytAdr = floor($BitAdr / 8);
    $BitOfs = $BitAdr % 8;
    $BitMask = 1;
    $BitMask = $BitMask << $BitOfs;
    return (array(
            'bytePos' => $BytAdr,
            'bitMask' => $BitMask
    ));
}

function getBaseMap($link) {
    $q = 'SELECT * FROM BASE WHERE id = 0';
    $r = mysqli_query($link, $q);
    if (! $r)
        return (null);
    $m = mysqli_fetch_assoc($r);
    mysqli_free_result($r);
    return ($m['map']);
}

function getBlocksMap($link, $IpHead) {
    $q = "SELECT * FROM BLOCKS WHERE IpHead = $IpHead";
    $r = mysqli_query($link, $q);
    if (! $r)
        return (null);
    $m = mysqli_fetch_assoc($r);
    mysqli_free_result($r);
    return ($m['map']);
}

function isBlocked() {
    global $slink;
    $ip = getUserIp();
    if($ip == "")
        return (BLOCK_ON_ERROR);
    $ip = ipToArray($ip);

    // here you can embed preliminary checks like ip[0] = 10 exit(0)
    // for unblocking or blocking address range 10 or 192 or 127 etc....

    // Look at base table base record.
    // map is a php string, which in fact is a good byte array
    $map = getBaseMap($slink); 
    if (! $map)
        return (BLOCK_ON_ERROR);
    $p = calculateBitPos($ip[0], $ip[1]);
    $c = ord($map[$p['bytePos']]);
    if (($c & $p['bitMask']) == 0)
        return (false); // No address blocked

    // Look at blocks table related record
    $map = getBlocksMap($slink, $p[0]);
    if (! $map)
        return (BLOCK_ON_ERROR);
    $p = calculateBitPos($ip[2], $ip[3]);
    $c = ord($map[$p['bytePos']]);
    return (($c & $p['bitMask']) != 0);
}

?> 

これが役立つことを願っています。

詳細についてご質問がございましたら、喜んでお答えいたします。

于 2013-03-28T10:23:57.773 に答える
11

iptables と ipset を使用して、トラフィックが www サーバーに到達する前にブロックします。

Web サーバーが同じマシン上にあると仮定して、INPUT チェーンのフィルター テーブルでブラックリストに登録された IP トラフィックをキャッチします。ルーターで IP をブロックしている場合は、FORWARD チェーンが必要になります。

最初に ipset を作成します。

ipset create ip_blacklist hash:ip

IP は次の方法で追加できます。

ipset add ip_blacklist xxx.xxx.xxx.xxx

ipset 一致ルールを iptables に追加します (ipset に一致するすべてのパケットをドロップします):

iptables --table filter --insert INPUT --match set --match-set ip_blacklist src -j DROP

これにより、www サーバーの前にブラックリストに登録されたトラフィックが停止します。

編集: デフォルトの最大サイズを調べる機会がありましたが、それは 65536 なので、100000 以上のエントリをサポートするにはこれを調整する必要があります:

ipset create ip_blacklist hash:ip maxelem 120000

ハッシュサイズを調整することもできます:

ipset create ip_blacklist hash:ip maxelem 120000 hashsize 16384(2 の累乗でなければなりません)

私の経験では、ipset ルックアップがシステムに与える影響はごくわずかです (~45000 エントリ)。ネット上には数多くのテストケースがあります。セットのメモリは制限要因です。

于 2013-10-26T05:42:46.727 に答える
5

コードで追加/削除する方法が必要な場合は、denyhostsをご覧ください。コードを使用して IP リストを維持するか、ソースにパッチを適用して、任意の場所から読み取ることができます。

于 2013-03-22T21:09:52.897 に答える
4

ipset と呼ばれる netfilter を使用したプロジェクトがあるため、リストに ip を追加または削除できます。このリストに対してルールを作成するだけです。

http://ipset.netfilter.org/

于 2013-03-31T09:48:08.740 に答える
3

IP をブロックしている場合は、実際にはファイアウォール レベルでこれを行う必要があります (望ましくない IP アドレスからのユーザーがシステムの奥深くまで侵入することは望ましくありません)。したがって、データベースにクエリを実行し、それに応じてファイアウォール構成ファイルを変更する bash スクリプトを作成することをお勧めします (これは、Web データベースに保存されている IP アドレスを利用するソリューションが必要であることを前提としています。そのような情報を保存するためのより良い場所がある可能性があります)。 )。

編集: @Populus が提案したように、PHP レベルで IP アドレスをブラックリストに追加する場合は、PHP でシステム コールを使用する方法に関するマニュアルを次に示します: http://php.net/manual/en/function.system .php

また、iptables を使用している場合に IP アドレスをブラックリストに追加するために必要なコマンドは次のとおりです: http://www.cyberciti.biz/faq/linux-iptables-drop/

于 2013-03-22T20:58:33.937 に答える
3


私はphpによる方法を知っています。この質問の冒頭で述べたように。

$ipList = []; // array list or from database
if (in_array(getIP(), $ipList)) {
    // Log IP & Access information
    header("https://www.google.com.ng/search?q=fool"); // redirect
    exit(); // exit
} 

私はあなたが書いたものを読みました。しかし、ちょっと待ってください。
なぜこれをしたいのかは重要ではありませんが、なぜこの状況で。
php へのアクセスを回避したいのは、その速度のため、または防止のため、およびすべてのページで関数を呼び出すのが非常に難しいためです。一部のIPがphpにアクセスするのを避ける唯一の理由が、テーマを避けてコンテンツを表示することである場合。
だから私はアイデアを得て、私はあなたにこの方法を提案します。
1 つのエントリ ポイントを使用します。

私はこのソリューションで作業しました。

最初に単純な htaccess を使用して、エントリ ポイントと呼ばれる 1 つのページ (index.php など) にすべての要求を送信します。
単純な書き換えルールを使用します。そのため、ユーザーが要求したときに

mysite.com/some/path/page.php or anything

htaccess は、url を変更せずに次のようなものを実行します。したがって、ユーザーは何も感じません。

mysite.com/index.php?r=some/path/page.php

そのため、すべてのリクエストが異なる $_GET['r'] パラメータを持つ 1 つのリクエストになりました。したがって、リクエストごとに index.php が実行されます。そして今、index.php でこのようなことを行うことができます

$ipList = []; // array list or from database
if (in_array(getIP(), $ipList)) {
    // Log IP & Access information
    header("https://www.google.com.ng/search?q=fool"); // redirect
    exit(); // exit
}
//if after this execute means the IP is not banned
//now we can include file that $_GET['r'] points to
include $_GET['r'];

とてもシンプルで、実際のものはとても複雑ですが、主なアイデアは同じです。どう思いますか?

于 2013-03-31T13:30:43.143 に答える
2

私たちのほとんどは、ファイアウォール レベルでブロックすることに同意しているようです。

ウェブサイトをリッスンして ips をブロックし、スクリプトを生成するプログラムを作成できます。

ip = getNextIpToBlock()
an = increment_unique_alphanum_generator()
script = generate_script(ip, an)

スクリプトは次のようになります ([an] は英数字の値で、[ip] はブロックする IP です)。

en [enter]
*password* [enter]
conf t [enter]
access-list [an] deny ip [ip] 0.0.0.0 any [enter]
access-group [an] in interface outside [enter]

次に、このスクリプトを、FW CLI へのリモート telnet または ssh 呼び出しを実行する別のプログラムにロードします。

ログアウトすることを忘れないでください。おそらく 100 ips ごとに、実行中の構成をコピーして構成を開始してください。

わかりませんが、ファイアウォールの制限について知りたいと思うかもしれません。

一番、

于 2013-03-31T20:59:12.037 に答える
0

私見、この質問を検討できるいくつかの角度があります

  1. ブロックする一意の IP アドレスのセットが非常に大きい。サーバーでそれらをブロックするのが早ければ早いほど、それらに浪費される処理能力が少なくなります. PHP から適切なシステム コールを使用して、ファイアウォールで IP を追加/削除できます。

上記のオプションを考慮すると、関連する質問は次のとおりです。

  • 彼らは頻繁に訪れますか?                               =>もしそうなら、解決策(1)が最善の策です。
  • ファイアウォールはそれを効率的に処理できますか? =>そうでない場合は、別の解決策を検討することをお勧めします。

これ.htaccessは私の 2 番目の選択肢です。

于 2013-03-31T19:54:40.790 に答える
0

リスト内の IP でジオルックアップを実行します。私自身の経験によると、ほとんどの悪意のある (つまり、スパム) 接続は中国から発信されています。同じことが当てはまり、中国にサービスを提供する必要が特にない場合は、ファイアウォール レベルで国全体を効率的にブロックできるかどうかを確認してください。

于 2013-03-26T20:10:46.000 に答える