66 votes

Comment Bloquer plus de 100 000 adresses IP Individuelles

Introduction

Comment Bloquer un grand nombre de IP address de votre application web/serveur. Évidemment, cela peut facilement être réalisé en PHP ou de tout langage de programmation

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

Ou À L'Aide De htaccess

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

Les questions

  • Essaie de bloquer un ensemble 100k plus individual IPs pas subnets
  • Essaie d'éviter que l'utilisateur arriver à PHP avant de bloquer ces IP
  • 100000+ est plus de 1,5 MO et c'est beaucoup si l'information chargement en htaccess tout le temps
  • Base de données de la propriété intellectuelle toujours en croissance ... et ils serait née d'ajouter dynamiquement des valeurs plus
  • Pour définir des interdictions d' iptables de 100000+ est tout simplement ridicule (Peut Être mal)

Idée Stupide

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

Question

  • Est-il possible pour htaccess pour obtenir la liste à partir de la base de données (Redis,Crunchbase,Mongo, MySQL ou même Sqlite) ... tout
  • Est-il visible solution pour gérer ce genre de problème dans la production
  • Je sais que la meilleure solution est - Block the IPs at the firewall level est-il possible de façon pragmatique, ajouter/supprimer IP du pare-feu

Enfin

Mon approche peut être totalement faux ... tout ce que je veux est visible une solution, car les spammeurs et les réseaux de zombies sont à la hausse ...

Veuillez cela n'a rien à voir avec DOS attaque son simple ... get lost response

Mise à jour

  • Pare-feu : Cisco PIX 515UR

64voto

Jon Lin Points 88615

Quelque chose que vous pouvez essayer est de garder une liste d'adresses IP que vous souhaitez bloquer dans un fichier texte ou de le convertir à une dbm fichier de hachage, puis utiliser mod_rewrite l' RewriteMap. Vous devez configurer votre serveur/vhost config. Vous ne pouvez pas initialiser une carte dans un fichier htaccess.

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

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

L' /path/to/deny_ips.txt fichier devrait ressembler à quelque chose comme ceci:

12.34.56.78 1
11.22.33.44 1
etc.

Essentiellement, une adresse IP que vous voulez refuser et d'un espace puis d'un "1". Toute la propriété intellectuelle dans ce fichier texte va provoquer le serveur renvoie un 403 Forbidden. Pour accélérer un peu les choses, vous pouvez utiliser l' httxt2dbm pour générer une dbm de hachage et vous devez alors définir la cartographie de la manière suivante:

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

Je ne suis pas sûr de ce que le gain de performance est pour l'utilisation de mod_rewrite comme ça avec beaucoup de IPs, mais un rapide test de référence sur apache 2.2 en cours d'exécution sur un 3Ghz i686 sous linux, la différence entre les 5 adresses ip dans la liste par rapport 102418 est négligeable. En fonction de abproduction, ils sont presque identiques.


S'attaquer à certaines questions:

Est-il possible de htaccess pour obtenir la liste à partir de la base de données (Redis,Crunchbase,Mongo, MySQL ou même Sqlite) ... tout

À l'aide d'une carte de réécriture, vous pouvez utiliser le bouton "prg" type de carte pour exécuter un programme externe pour un type de mappage. Vous pouvez ensuite écrire un perl, php, etc. script de parler à une base de données afin de chercher une adresse IP. Notez également que les mises en garde inscrites en vertu de la "Prudence". Vous pouvez utiliser cette carte comme vous le feriez pour n'importe quelle autre carte (RewriteCond ${deny_ips:%{REMOTE_ADDR}|0} !=0). Cela aurait pour effet de créer un goulot d'étranglement pour toutes les demandes. Pas la meilleure solution pour en parler à une base de données.

Dans apache 2.4, il existe une dbd/fastdbd le type de carte, qui vous permet de créer des requêtes par le biais de mod_dbd. C'est une bien meilleure option et la mod_dbd module gère les connexions à la base de données, les pools de connexions, etc. Donc, la définition de carte ressemblerait à quelque chose comme:

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

En supposant que vous avez une table "deny_ips" avec 2 colonnes "source" (l'adresse IP) et "active" (1 pour les actifs, 0 pour les inactifs).

Est-il visible solution pour gérer ce genre de problème dans la production

Si vous êtes le stockage de toutes les IPs bloquées dans la base de données, c'est une question de gestion du contenu de votre table de base de données. Si vous êtes à l'aide de la dbm type de carte, je sais au moins que perl a un DBI pour la gestion des fichiers dbm, donc vous pouvez l'utiliser pour ajouter/supprimer des entrées IP à partir de la liste de refus. Je n'ai jamais utilisé avant, donc je ne peux pas vraiment en dire beaucoup à ce sujet. Gestion d'un fichier de texte plat va être beaucoup plus compliqué, surtout si vous prévoyez sur la suppression d'entrées, et pas seulement ajouter. En dehors de l'utilisation d'une base de données et apache 2.4 de l'mod_dbd, je ne pense pas qu'aucune de ces solutions sont en dehors de la zone de production ou de prêt. Cela va demander un travail personnalisé.

Je sais que la meilleure solution est de Bloquer les IPs au niveau de pare-feu est-il possible de façon pragmatique, ajouter/supprimer IP du pare-feu

Pour IPtables, il y a une interface perl qui est marqué en tant que Bêta, mais je n'ai jamais utilisé avant. Il y a libiptc mais selon netfilter faq:

Est-il une API C/C++ pour l'ajout/suppression de règles?

La réponse est malheureusement Non.

Maintenant, vous pourriez penser " mais qu'libiptc?'. Comme cela a été souligné à de nombreuses reprises sur la liste de diffusion(s), libiptc fut JAMAIS destiné à être utilisé comme une interface publique. Nous ne garantissons pas une interface stable, et il est prévu de le supprimer dans la prochaine incarnation de linux de filtrage de paquets. libiptc est trop faible couche pour être utilisé raisonnablement de toute façon.

Nous sommes bien conscients qu'il y a un manque fondamental pour une telle API, et nous travaillons sur l'amélioration de cette situation. Jusqu'alors, il est recommandé d'utiliser system() ou ouvrir un tuyau dans stdin de iptables-restore. Ce dernier vous permettra de meilleures performances.

Donc je ne sais pas comment viable libiptc solution est que si il n'y a pas d'API de stabilité.

33voto

Ihsan Points 1861

UN AUTRE POINT DE VUE

Bonjour. Vous pouvez vérifier si une adresse est bloqué ou pas, via l'accès à deux octets dans deux morceaux de données chaque 8 KO de long. Oui, je suis sérieux... s'il vous Plaît être patient car il faut un peu long à expliquer.

LA THÉORIE

Une adresse IP est une adresse, en fait un 4 nombre d'octet.

La question est, que si nous la faire à l'adresse de positions de bits?.

La réponse: eh Bien ok, nous allons avoir

  2^32 = 4 Giga Bits 

de l'espace d'adressage et qui va prendre

 4Gb/8 = 512 Mega Bytes

de l'allocation. Ouch! Mais ne vous inquiétez pas, nous n'allons pas bloquer tout le ipverse et 512 mo est une exagération.

Cela peut nous ouvrir un chemin vers la solution.

Le Lilliputien Cas

Pensez à un Lilliputien monde, il existe seulement des adresses ip de 0 à 65535. Si les adresses sont comme de 0,1 ou de 42.42 jusqu'à 255.255.

Maintenant, le Roi de ce monde veut bloquer plusieurs L-IP (lilliput ip).

D'abord, il construit un virtuel 2D bit map qui est de 256 * 256 bits qui prend :

 64 K Bits = 8 K Bytes.

Il décide de bloc méchant "révolution" du site ce qu'il déteste parce qu'il est le roi, l'adresse est 56.28, par exemple.

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

Il ouvre le fichier map, accède à 1795th octet et définit le bit 4 (|16), puis de l'écrit à marquer le site comme bloqué.

Lors de son scénario voit le 56.28, il fait le même calcul et regarde le peu, et si elle est définie, les blocs de l'adresse.

Maintenant, quelle est la morale de l'histoire? Eh bien, nous pouvons utiliser ce lilliputien de la structure.

LA PRATIQUE

Le Monde Réel De Cas

Nous pouvons appliquer le Lilliputien de cas du monde réel, avec une "utiliser quand vous en avez besoin" approche puisque l'allocation d'une 512 mo de fichier n'est pas un bon choix.

Pensez à une table de base de données nommé BLOCS avec des entrées comme:

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

Et une autre table avec une seule entrée à la structure ci-dessous nommée BASE

Map        : 8KB BLOB(fixed size).

Maintenant, disons que vous avez une entrée d'adresse 56.28.10.2

Script accède à la BASE de la table et obtient la Carte.

Il regarde le supérieur de l'ordre des numéros 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)

Regarde octet 1795 bits 4 à la Carte.

Si le bit n'est pas défini, aucune autre opération n'est nécessaire, et donc il n'y a pas d'adresse ip bloquée dans la gamme 56.28.0.0 - 56.28.255.255 .

Si le bit est défini, alors le script accède à la table des BLOCS.

Le supérieur de l'ordre des numéros IP ont été 56.28 qui donne 14364 ainsi, le script de requêtes de la table des BLOCS avec index IpHead = 14364. Extrait de l'enregistrement. L'enregistrement doit exister car elle est marquée à la BASE.

Le Script fait le calcul pour un ordre inférieur de l'adresse IP

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

Puis il vérifie si l'adresse est bloquée en regardant les 2 bits de l'octet 320 de la Carte du champ.

Travail de fait!

Q1: Pourquoi utilisons-nous de BASE à tous, nous avons pu interroger directement les BLOCS avec 14364.

A1: Oui, on pourrait, mais à la carte de BASE de recherche sera plus rapide, puis BTREE la recherche de tout serveur de base de données.

Q2: Quelle est la EntryCount champ dans la table des BLOCS?

A2: C'est le nombre d'adresses ip bloquées dans la carte de terrain dans le même dossier. Donc, si nous débloquer l'ip et EntryCount atteint 0 qui BLOQUE disque devient inutiles. Il peut être effacé et le bit correspondant sur la BASE de la carte sera annulée.

À mon humble avis, cette approche sera aussi rapide que l'éclair. Aussi pour le blob de l'allocation de 8K par enregistrement. Depuis db serveurs de garder les gouttes de séparer les fichiers, les systèmes de fichiers 4K, 8K ou des multiples de 4K pagination va réagir vite.

Dans le cas des adresses bloquées sont trop dispersées

Eh bien, c'est un sujet de préoccupation, ce qui fera de la base de données de la table des BLOCS pour augmenter inutilement.

Mais pour de tels cas, l'alternative est d'utiliser un 256*256*256 peu de cube qui est de 16777216 bits, égalant à 2097152 octets = 2 MO.

Pour notre exemple précédent Ip Plus grande résolution est :

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

Donc de BASE deviendra un fichier de 2 mo au lieu d'un db enregistrement de la table, qui sera ouvert (fopen, etc.) et peu seront abordées par la recherche (comme fseek, ne jamais lire le contenu du fichier, inutile) puis accéder à la table des BLOCS avec la structure ci-dessous:

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. 

Voici l'exemple de code php pour bloquer la vérification de bitplane-bitplane (8K 8K) version:

Remarque: Ce script peut être optimisé via l'élimination de plusieurs appels, etc.. Mais écrit comme ça pour garder facile à comprendre.

<?
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);
}

?> 

J'espère que cette aide.

Si vous avez des questions sur les détails, je serai heureux de répondre.

8voto

Freedom_Ben Points 3366

Vous avez besoin de le faire avec un pare-feu externe, pas en PHP. Je recommande pfSense ou PF. Je l'ai utilisé avant et il est très facile à utiliser, très intuitif, et très puissant. C'est le choix de la meilleure sys-admins. Je l'exécute sur FreeBSD, mais il fonctionne très bien sur OpenBSD. Je suis un Linux mec tellement il me fait mal de le dire, mais ne pas essayer de le faire fonctionner sur Linux. BSD est facile, et vous pouvez le comprendre rapidement.

Une fonctionnalité impressionnante pour pfSense est la possibilité de configurer à l'aide de scripts et de limiter la configuration de l'accès à une seule interface réseau (de sorte que les seules choses sur le réseau local peut le configurer). Il a aussi un couple de ID10T niveau de fonctionnalités pour vous garder de couper votre propre accès accidentellement.

Vous devriez aussi être conscient que beaucoup de spammeurs pouvez passer IPs rapidement en utilisant des choses comme Tor. Pour y remédier, vous devez inclure dans votre liste de blocage des adresses qui sont connus des nœuds de sortie tor (cette liste est disponible à partir de plusieurs endroits).

8voto

Donald Chisholm Points 65

Bloquer le trafic avant qu'il n'atteigne le serveur www de l'utilisation de iptables et ipset.

Attraper la liste noire du trafic IP dans la table de filtre de la chaîne d'ENTRÉE en supposant que votre serveur web est sur la même machine. Si vous êtes le blocage des IPs sur un routeur, vous voulez la chaîne FORWARD.

D'abord créer le ipset:

ipset create ip_blacklist hash:ip

IPs peuvent être ajoutés via:

ipset add ip_blacklist xxx.xxx.xxx.xxx

Ajouter le ipset règle match à votre iptables (CHUTE de tous les paquets qui correspondent à ipset):

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

Cela va arrêter la liste noire de la circulation avant que le serveur www.

Edit: j'ai eu l'occasion de le regarder jusqu'à la taille maximale par défaut et il est de 65536 donc, vous devez ajuster les ce à l'appui de 100000+ entrées:

ipset create ip_blacklist hash:ip maxelem 120000

Vous pouvez également ajuster la valeur de hachage de taille:

ipset create ip_blacklist hash:ip maxelem 120000 hashsize 16384 (Doit être une puissance de 2)

Mon expérience est ipset de recherche a un effet négligeable sur mon système (~45000 entrées). Il y a un certain nombre de cas de test sur le net. Mémoire pour le jeu est un facteur limitant.

5voto

ethrbunny Points 5487

Si vous voulez un moyen d'ajouter / supprimer via le code jeter un oeil à denyhosts. Vous pouvez soit maintenir la liste des IP via le code ou le correctif de la source à lire à partir de l'emplacement que vous souhaitez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X