Program Tip

100,000 개 이상의 개별 IP 주소를 차단하는 방법

programtip 2020. 11. 14. 10:58
반응형

100,000 개 이상의 개별 IP 주소를 차단하는 방법


소개

IP address웹 응용 프로그램 / 서버에서 많은 수를 어떻게 차단합니까? 분명히 그것은 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 데이터베이스는 계속 성장하고 있으며 더 많은 가치를 동적으로 추가해야합니다.
  • iptables100000+ 대한 금지를 설정하는 것은 우스꽝 스럽습니다 (잘못되었을 수 있습니다)

어리석은 생각

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

시도해 볼 수있는 것은 차단하려는 IP 주소 목록을 텍스트 파일에 보관 하거나 dbm 해시 파일 로 변환 한 다음 mod_rewrite의 RewriteMap. 서버 / vhost 설정에서 설정해야합니다. 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 "맵 유형을 사용하여 매핑 유형에 대한 외부 프로그램을 실행할 수 있습니다. 그런 다음 IP 주소를 조회하기 위해 데이터베이스와 통신하는 perl, php 등의 스크립트를 작성할 수 있습니다. 또한 "주의"아래에 나열된주의 사항에 유의하십시오. 그런 다음 다른지도 ( RewriteCond ${deny_ips:%{REMOTE_ADDR}|0} !=0) 와 마찬가지로이지도를 사용합니다 . 이것은 본질적으로 모든 요청에 ​​대한 병목 현상을 만듭니다. 데이터베이스와 대화하기위한 최상의 솔루션은 아닙니다.

하지만 아파치 2.4에서는,이 DBD / fastdbd 당신을 통해 쿼리를 만들 수 있도록지도 유형, mod_dbd . 이것은 훨씬 더 나은 옵션이며 mod_dbd 모듈은 데이터베이스에 대한 연결, 풀 연결 등을 관리합니다. 따라서 맵 정의는 다음과 같습니다.

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

2 개의 열 " source "(IP 주소) 및 " active "(활성의 경우 1, 비활성의 경우 0 ) 이있는 " deny_ips " 테이블이 있다고 가정합니다 .

프로덕션에서 이러한 종류의 문제를 관리 할 수있는 가시적 인 솔루션이 있습니까?

차단 된 모든 IP를 데이터베이스에 저장하는 경우 데이터베이스 테이블의 내용을 관리해야합니다. dbm 맵 유형을 사용하는 경우 적어도 perl에 dbm 파일 관리를 위한 DBI가 있다는 것을 알고 있으므로이를 사용하여 거부 목록에서 IP 항목을 추가 / 제거 할 수 있습니다. 전에 사용 해본 적이 없어서 그다지 말할 수 없습니다. 플랫 텍스트 파일을 관리하는 것은 특히 항목을 추가하는 것이 아니라 항목을 제거하려는 경우 훨씬 까다로울 것입니다. 데이터베이스와 아파치 2.4의 mod_dbd를 사용하는 것 외에는 이러한 솔루션이 즉시 사용 가능하거나 프로덕션 준비가되어 있지 않다고 생각합니다. 맞춤 작업이 필요합니다.

가장 좋은 해결책은 방화벽 수준에서 IP를 차단하는 것입니다. 실제로 방화벽에 IP를 추가 / 제거 할 수있는 방법이 있습니까?

IPtables의 경우 베타로 표시된 펄 인터페이스 가 있지만 이전에 사용한 적이 없습니다. 거기 하기 libiptc 하지만에 따라 넷 필터의 자주 묻는 질문 :

규칙 추가 / 제거를위한 C / C ++ API가 있습니까?

안타깝게도 대답은 아니오입니다.

이제 '하지만 libiptc는 어떻습니까?'라고 생각할 수 있습니다. 메일 링리스트 (들)에서 여러 번 지적했듯이 libiptc는 결코 공용 인터페이스로 사용 되지 않았습니다 . 우리는 안정적인 인터페이스를 보장하지 않으며, 다음 리눅스 패킷 필터링에서이를 제거 할 계획입니다. libiptc는 어쨌든 합리적으로 사용하기에는 너무 낮은 계층입니다.

우리는 그러한 API에 근본적인 부족이 있음을 잘 알고 있으며 그 상황을 개선하기 위해 노력하고 있습니다. 그때까지는 system ()을 사용하거나 iptables-restore의 stdin으로 파이프를 여는 것이 좋습니다. 후자는 더 나은 성능을 제공합니다.

그래서 API 안정성이 없다면 libiptc 솔루션이 얼마나 실행 가능한지 모르겠습니다.


또 다른 관점

여보세요. 각 8KB 길이의 두 데이터 청크에서 2 바이트에 액세스하여 주소가 차단되었는지 여부를 확인할 수 있습니다. 예, 진심입니다 ... 설명하는 데 시간이 조금 걸리니 기다려주세요.

이론

IP 주소는 주소이며 실제로는 4 바이트 숫자입니다.

문제는 비트 위치를 처리하도록 만들면 어떨까요?

답 : 좋습니다.

  2^32 = 4 Giga Bits 

주소 지정 공간의

 4Gb/8 = 512 Mega Bytes

할당. 아야! 그러나 걱정하지 마십시오. 우리는 ipverse의 모든 것을 차단하지 않을 것이며 512MB는 과장입니다.

이것은 우리에게 해결책으로가는 길을 열어 줄 수 있습니다.

Lilliputian 사건

0에서 65535까지의 IP 주소 만 존재하는 Lilliputian 세계를 생각해보십시오. 따라서 주소는 0.1 또는 42.42에서 255.255까지입니다.

이제 King of this world는 여러 L-IP (lilliput 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을 볼 때 동일한 계산을 수행하고 비트를보고, 설정된 경우 주소를 차단합니다.

이제 이야기의 교훈은 무엇입니까? 이 lilliputian 구조를 사용할 수 있습니다.

연습

실제 사례

512MB 파일을 할당하는 것은 좋은 선택이 아니기 때문에 Lilliputian 사례를 "필요할 때 사용"접근 방식으로 실제 세계에 적용 할 수 있습니다.

다음과 같은 항목이있는 BLOCKS라는 데이터베이스 테이블을 생각해보십시오.

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

그리고 아래에 BASE라는 구조의 항목이 하나만있는 또 다른 테이블

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)

그런 다음 필드 맵의 320 바이트 중 2 비트를보고 주소가 차단되었는지 확인합니다.

완료되었습니다!

Q1 : BASE를 사용하는 이유는 무엇입니까? 14364로 BLOCKS를 직접 쿼리 할 수 ​​있습니다.

A1 : 예, 가능하지만 BASE 맵 조회가 데이터베이스 서버의 BTREE 검색보다 빠릅니다.

Q2 : BLOCKS 테이블의 EntryCount 필드는 무엇입니까?

A2 : 동일한 레코드의 맵 필드에서 차단 된 IP 주소의 수입니다. 따라서 IP 차단을 해제하고 EntryCount가 0에 도달하면 BLOCKS 레코드가 불필요 해집니다. 지울 수 있으며 BASE 맵의 해당 비트가 설정 해제됩니다.

IMHO이 접근 방식은 번개처럼 빠릅니다. 또한 Blob 할당의 경우 레코드 당 8K입니다. db 서버는 blob을 별도의 파일에 보관하므로 4K, 8K 또는 4K 페이징의 배수가있는 파일 시스템은 빠르게 반응합니다.

차단 된 주소가 너무 분산 된 경우

이는 데이터베이스 BLOCKS 테이블이 불필요하게 증가하게 만드는 문제입니다.

그러나 그러한 경우 대안은 길이가 16777216 비트 인 256 * 256 * 256 비트 큐브를 사용하는 것입니다. 이는 2097152 바이트 = 2MB입니다.

이전 예제의 경우 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);
}

?> 

이게 도움이 되길 바란다.

세부 사항에 대한 질문이 있으시면 기꺼이 답변 해 드리겠습니다.


You need to do this with an external firewall, not in PHP. I recommend pfSense or PF. I have used it before and it is very easy to use, very intuitive, and extremely powerful. It is the choice of the best sys-admins. I run it on FreeBSD, but it works great on OpenBSD as well. I am a Linux guy so it pains me to say this, but don't try to run it on Linux. BSD is easy, and you can figure it out quickly.

An awesome feature for pfSense is the ability to configure using scripts and restricting the configuration access to a single network interface (so that only things on the LAN can configure it). It also has a couple of ID10T level features to keep you from cutting off your own access accidentally.

You should also be aware that many spammers can switch IPs quickly using things like Tor. To fix this you should include in your block list the addresses that are known tor exit nodes (this list is available from various places).


Block the traffic before it reaches the www server using iptables and ipset.

Catch the blacklisted IP traffic in the filter table of the INPUT chain assuming your web server is on the same machine. If you are blocking IPs on a router you will want the FORWARD chain.

First create the ipset:

ipset create ip_blacklist hash:ip

IPs can be added via:

ipset add ip_blacklist xxx.xxx.xxx.xxx

Add the ipset match rule to your iptables (DROP all packets match to ipset):

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

This will stop the blacklisted traffic before the www server.

Edit: I had a chance to look up the default maximum size and it is 65536 so you will need to adjust this to support 100000+ entries:

ipset create ip_blacklist hash:ip maxelem 120000

You can also tweak the hash size:

ipset create ip_blacklist hash:ip maxelem 120000 hashsize 16384 (Must be a power of 2)

My experience is ipset lookup has negligible effect on my system (~45000 entries). There are a number of test cases on the net. Memory for the set is a limiting factor.


If you want a way to add / remove via code take a look at denyhosts. You could either maintain the IP list via code or patch the source to read from whatever location you want.


There is a project with netfilter for that called ipset so you can add or remove ip to a list and you just have to create a rule against this list

http://ipset.netfilter.org/


If you're blocking IPs, you really should be doing this at the firewall level (you don't want users from unwelcome IP addresses getting very far into your system). Thus, I suggest writing a bash script that queries the database and modifies your firewall configuration file accordingly (this assumes that you want a solution which utilizes IP addresses stored in your web database -- there very well might be a better place to store such information).

EDIT: If you wanted to add IP addresses to the blacklist at the PHP level, as @Populus suggested, here is the manual on how to use system calls in PHP: http://php.net/manual/en/function.system.php

And here are the commands you would need to use to add an ip address to your blacklist if you're using iptables: http://www.cyberciti.biz/faq/linux-iptables-drop/


I know a way
its by php. as you mentioned in the very beginig of this question.

$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
} 

I read thing you have wrote. but just wait a minute.
why you want to do this.is not important.but why with this situation.
I mean why would you want to avoid accessing php because of its speed or just because of preventing and because its so hard to call the function in all pages? if the only reason of avoiding some ip from accessing php is.avoiding theme to see contents.
so I got an idea and I.suggest you this way.
using one entry point.

I have worked with this solution.

first with a simple htaccess you send all requests to one page called entry point.(like index.php)
with a simple rewriting rule i'll give it to you. so when the user requests

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

htaccess will execute something like the following without changing the url. so the user would not feel anything.

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

so every request became one request with different $_GET['r'] params. so for evey request we will have index.php executed. and now we can do somthing like this in 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'];

its so simple.and its real one is so complicated.but the main idea is the same. what do you think?


It seems that most of us agree to block at the firewall level.

You could have a program that listens to your website for ips to block and generates a script:

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

script would look something like this (where [an] is an alphanumeric value and [ip] is the ip you block):

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]

Then you load this script to another program that executes remote telnet or ssh calls to your FW CLI.

Don't forget to logout and maybe every 100 ips you copy the running config to start config.

I don't know but you may want to know now what are the limitations for your firewall.

Best,


Do a geo-lookup on the IPs in your list. My own experience has shown most malicious (i.e. spam) connections have originated from China. If you find the same to be the case for you, and you have no specific need to serve China, see if you can efficiently block the entire country at the firewall level.


IMHO, there are several angles from which this question can be considered

  1. You have a very large set of unique IP addresses to block. The earlier you block them on your server, the less processing power you will waste on them. You can add/remove IPs in your firewall through appropriate system calls from PHP.

Considering the above option, the only relevant questions are:

  • Do they visit often?                               =>  If so, then solution (1) is your best bet.
  • Can your firewall handle it efficiently?   =>  If not, you may want to consider an other solution.

The .htaccess would be my second choice.

참고URL : https://stackoverflow.com/questions/15579620/how-to-block-100-000-individual-ip-addresses

반응형