Notre magasin

Rue Albert 1er, 7

6810 Pin - Chiny

(/fax: 061/32.00.15

16. Mise en ligne d'un site

Formations informatiques en ligne sur YBET.be
Office Internet Techniques
Access Formation Internet PC et périphériques
Cours Excel PHP - MySQL Equipements réseaux
Powerpoint Pour débuter son site Dos et Windows
ACCUEIL Forum webmasters Nous contacter

Script PHP de protection de sites contre le piratage

Quelques explications de départ - Qu'est ce qui est bloqué ou non - Requêtes Mysql de création des tables - Détection en PHP - Code à insérer en début de page (avant <head>).

Dans une des news publiée sur ce site, j'ai donné quelques explications sur des visiteurs d'un site: Les autres pirates du web. Comme membre du forum Webrankinfo, je répond souvent ces derniers mois à des réponses sur des tentatives de copies, aspirateurs de sites, ... En même temps, le programme détecte des essais d'injection SQL: ces tentatives sont souvent automatiques avec un nombre d'essais de paramêtres différents sur la page en un minimum de temps. Une solution supplémentaire est également utilisée, mais pas expliquée sur cette page.

Si vous avez lu l'article, vous savez déjà que ce site et d'autres sont protégés contre différentes tentatives mal vues par le webmaster depuis fin 2014. Petite remarque, le programme développé ici a été modifié depuis (et nettement ammélioré) notamment au niveau des doubles visites sur une même page: pour recevoir le développement utilisé actuellement ou pour une aide pour la mise en place sur votre site, vous pouvez utiliser le formulaire de contact.

Le programme n'utilise que du PHP, pas de javascript. Que la visite sur une page soit un robot ou un réel visiteur n'intervient pas: toute visite sur une page protége est reprise dans une table. Tous visiteur indélicat provoque le blocage sur toutes les pages du site de cette adresse IP. Même mieux, toute visite indélicate sur un site entraîne également le blocage sur tous les autres sites protégés sur le même serveur. Pour les débutants, comprendre les fonctions utilisées pour récupérer les différents paramètres de la page sont expliquées sur le cours PHP de ce site (fonctions standards).

Le script complet reprend:

1. mise dans une table des visiteurs du site avec différentes informations publiques: date et heure, adresse IP et host, user_agent, page précédant la visite, site et page "vue" par le visiteur.

2. rassemblement dans une deuxième table des adresses IP bloquée: nombre de visites trop importantes en un minimum de temps. Renvoi automatique d'une erreur 403 sur cette adresse. Les visites suivantes ne sont plus reprises dans la table visiteurs

3. mise dans une troisième table des visites des principaux robots de moteurs: Google, Bing, yahoo. En effet, certaines adresses ne sont jamais bloquées

Pour l'instant, les résultats sont uniquement accessibles par accès direct aux trois tables, seules quelques petits rapports sont automatiques. Avec un peu d'habitude, cette méthode ne pose pas de problèmes pour analyser les résultats. Le programme fait quasiment la même chose que la vérification des logs du serveur sauf qu'il n'affiche pas les adresses IP bloquées par .htaccess, par un firewall installé sur le serveur, ni par le programme) et n'affiche pas les téléchargements d'images. De fait, c'est plus facile à analyser. Le calcul des masques et des blocages par CIDR est expliqué ici.

Quelques explication de départ.

1. un visiteur peut venir à partir d'une page ou non. Sans page précédante, le visiteur peut être un robot mais aussi des systèmes d'exploitation spécifiques, des redirections (une recherche sur le moteur de recherche de QWANT ou certains smartphones par exemple), ... Ceux-ci peuvent donc être n'importe quoi. Pour éviter une erreur avec la commande PHP $_SERVER["HTTP_REFERER"], le champ est remplacé par direct.

2. Certains navigateurs vérifient automatiquement si des fichiers sont présents images miniatures. Un visiteur qui ouvre plusieurs pages en entrant (la page suivie de pages d'erreur immédiatement) n'est pas forcément un visiteur non standard.

3. Certains navigateurs (ou configuration) rouvrent plusieurs fois la page immédiatement. Avec une protection contre le vol d'images sur les sites, quasiment toutes les visites provenant de Google image réouvrent la page.

4. Une configuration particulière bloque toutes les manipulations d'adresses. Si l'adresse réelle de la page n'est pas celle indiquée, le visiteur est d'office bloqué. Tous paramètres supplémentaires présent dans l'URL est automatiquement redirigé en erreur 403. Dans mon cas, n'utilisant pas (ou peu) de CMS, c'est facile. Pour d'autres, l'adresse effective peut-être directement reprise dans la base de donnée contenu par programmation. Dans le script de base, il y quand même une protection contre les injections SQL: tout simplement parce que ce genre de tentative envoie des commandes très rapidement à la suite des autres.

De fait, le programme ne travaille pas directement sur un nombre de pages vues pendant un labs de temps pour bloquer l'adresse IP mais sur un nombre de pages vues différentes. Une fois le nombre de pages maximum vues (dans ma configuration: 3) en X secondes (dans ma configuration, entre 3 et 10), le programme bloque l'accès au site dès le début de la visite suivante. En plus, dans la configuration, d'autres blocages sont exécutés suivant quelques pages précédantes (spamsmeurs notoires en faisant croire à de vrais liens externes, spécialité de beaucoup de russes, mais aussi de buttons-for-your-website.com (en fait sharebutton.net), 100dollars-seo.com/try.php et best-seo-offer.com/try.php (en fait semalt.com), aspirateurs de sites connus (sans user_agent modifié) qui sont renvoyés directement sur le site de téléchargement de l'aspirateur, ... Ces tests complémentaires sur le user_agent ou page précédente peuvent être interdites ou renvoyées vers l'envoyeur.

Qu'est ce qui est bloqué ou pas en pratique?

On vient de voir les aspirateurs mais d'autres spécialistes du spams sont aussi bloqués automatiquement. Une large partie des adresses bloquées essayent de spamsmer le forum sans être connecté: principalement russes et anciens bloc des pays de l'est comme l'Ukraine ou la Pologne mais aussi chinois. Avant d'installer le programme de blocage, trois fois plus de pages étaient vues par jour par ces techniques par ces pays que le nombre de visiteur réels détectés par les outils de statistiques standards: sur ce site, j'utilise Google Analytic et XITI en parallèle.

Une partie des tentatives viennent de serveurs proxy (tor, bien qu'officiellement utilisé par les dissidents de pays dictatoriaux, est un bel exemple) mais aussi d'autres serveurs piratés. Pourtant, le programme ne bloque pas automatiquement les tentatives d'utilisation des failles de différents CMS: le programme ne reprend que les erreurs en 404.

Toutes les adresses IP bloquées ne sont pas forcément des tentatives de bricolages au sens large: il est important de ne pas mettre un délai de vérification trop long (comme 15 secondes) mais plutôt 3-4 secondes. Une fois une adresse IP bloquée, vous pouvez la laisser (elle restera bloquée indéfiniment) soit la supprimée et l'adresse IP peut de nouveau visiter les pages normalement. Vous devez régulièrement vérifier les adresses bloquées pour débloquer des visiteurs standards en fonction de la table visiteur. Et même vérifier la table visiteur de temps en temps pour en bloquer d'autres.

Ce système ne blocage ne permet pas de détecter les visites sur d'autres ports TCP ou UDP que le TCP 80 (443 si votre site est en https). En pratique, le serveur Internet est configuré pour utiliser le firewall IPtables. Une fois une erreur grave détectée (par ce système de protection ou via un blocage du firewall), je bloque non seulement l'adresse mais toute la plage liée au fournisseur d'hébergement ou d'accès par des règles dans IPTABLE (le blocage peut être fait également par .htaccess). Pratiquement toutes les plages russes, chinoises, ukrainiennes, sud Coréennes, ... se font bloquer à fait par cette méthode mais aussi des hébergeurs Français, allemands, néerlandais, américains et belges (je ne suis pas raciste).

Pour détecter si une adresse est utilisée normalement ou par une plage de serveurs, un proxy: j'utilise de simples recherches sur Google. Mais ... certains sites annoncent comme spamsmeur des IP parfaitement valides après une seule tentative et continue à l'afficher. Les adresses des pays africains (+ Madagascar) sont souvent reprises comme telles et peuvent être réouvertes).

La création des tables

Téléchargement de création des tables en mode texte. Pour les 3 tables: uid est un champ auto-incrémenté, date_heure reprend la date et l'heure de l'inscription dans les tables . IP reprend l'adresse IPv4 du visiteur. ip_decimal est calculé en fonction de l'adresse IP. Host est renvoyé par php en fonction de l'adresse IP.

1. La table visiteur: visiteurip peux être remplacé par le nom de votre choix. C'est la table qui reprend les adresses visitées.

host: renvoyé par PHP

filename: la page visitée

site: est déterminé par le script en fonction de la page visitée

precedent: page précédente du visiteur

user_agent: récupéré par l'en-tête du navigateur du visiteur

x_forward: adresses de redirection (quasiment jamais remplie).

2. La table robot: le nom de la table robotip peut également être modifié

host: de nouveau renvoyé par PHP

Filename: la page visitée sans le nom de domaine

site: de nouveau renvoyé par le dossier effectif utilisé par le serveur

3. La table bloque: bloqueip peut être remplacé. Le champ "remarque" est à utiliser manuellement, il n'est pas rempli par le script. Le champ "Serveur" n'est plus utilisé, il détectait également les bbox des visiteurs standards.

Le script PHP de détection

Scripts de détection et d'appel en mode texte

Le fichier s'appelle dans mon cas ip.php, il va être appelé dans la partie suivante. Comme d'habitude dans mes développements, le fichier start.php reprend la connexion à la base de donnée (à modifier suivant vos propres codes de connexion), une fonction peut-être utilisée.

<?php
if(!mysql_connect('localhost','utilisateur','mot_passe')){
Echo'Connection Impossible';
exit();
} else{
// Echo'Connexion réussie';
}
Mysql_select_db('base_donnee');
?>

Si vous avez modifié le nom des tables ci-dessus, il doit également être remplacé dans ce script.

<?php

// -- récupération de l'adresse IP
$tableau=array();
$ip= ADDSLASHES($_SERVER["REMOTE_ADDR"]);
// echo $ip."<br>";
$tableau=explode(".",$ip);
$ipdecimal= intval($tableau['3']) + (intval($tableau['2'])*256) + (intval($tableau['1'])*256*256)+ (intval($tableau['0'])*256*256*256);
// Connexion à la base de donnée
include ('start.php');

// - début de vérification si l'adresse IP est déjà bloquée. Si

$requete="select ip from bloqueip WHERE ipdecimal_min <='$ipdecimal' AND ipdecimal_max >='$ipdecimal'";
$resultat=mysql_query($requete);
$ligne=mysql_num_rows($resultat);

if ($ligne>0)
{
// adresse déjà bloquée
header("HTTP/1.1 403 Forbidden");
exit();
}

// --------------------------------- fin de vérification si bloqué.


$host= ADDSLASHES(gethostbyaddr($_SERVER['REMOTE_ADDR']));
$filename=ADDSLASHES($_SERVER["SCRIPT_FILENAME"]);

// on utilise l'adresse réelle du dossier utilisateur.
$page=(strstr($filename,"/www/");

$site =STR_REPLACE($page,"",$filename);
$site =STR_REPLACE("/home/","",$site);

$page1 =STR_REPLACE("/www/","",$page);
$page=$_SERVER['REQUEST_URI'];

if (isset ($_SERVER["HTTP_REFERER"]))
{
$precedent= mysql_real_escape_string($_SERVER["HTTP_REFERER"]);
}
else
{
$precedent="Direct";
}

$user_agent= mysql_real_escape_string($_SERVER["HTTP_USER_AGENT"]);

//-- Vérification de redirection ...
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$x_forward = ADDSLASHES($_SERVER['HTTP_X_FORWARDED_FOR']);
}
else
{
$x_forward='';
}
// -- début suppression copieurs par différentes méthodes.
// Dans mon script personnel, il est plus important.
if (strpos(STRTOLOWER($user_agent),"httrack")!==false)
{
// httrack détecté
header("HTTP/1.1 403 Forbidden");
exit();
}
elseif (strpos(STRTOLOWER($user_agent),"indy")!==false)
{
// Free download manager
die('<meta http-equiv="refresh" content="0; URL=http://www.freedownloadmanager.org/">');
}elseif (empty($host))
{
header("HTTP/1.1 403 Forbidden");
exit();
}
elseif (strpos(STRTOLOWER($user_agent),"ia_archiver")!==false)
{
// un copieur de site qui permet l'indexation de son propre site par Google: duplicate content.
header("HTTP/1.1 403 Forbidden");
exit();
}
// ----- fin suppression par HOST
if (strpos(STRTOLOWER($precedent),"best-seo")!==false)
{
die('<meta http-equiv="refresh" content="0; URL=http://semalt.com">');
} elseif (strpos(STRTOLOWER($precedent),"semalt")!==false)
{
die('<meta http-equiv="refresh" content="0; URL=http://semalt.com">');
} elseif (strpos(STRTOLOWER($precedent),"buttons-for-website")!==false)
{
die('<meta http-equiv="refresh" content="0; URL=http://sharebutton.net">');
} elseif (strpos(STRTOLOWER($precedent),"100dollars")!==false)
{
// suppression de semalt
die('<meta http-equiv="refresh" content="0; URL=http://www.phoenixhollo.com">');
}

// fin verification spider

include ('start.php');

// détection de Googleboot, ip = X.X.X.X, host=crawl-X-X-X-X.googlebot.com user_agent contient http://www.google.com/bot.html , plage d'adresses IP

$depart= "crawl-".$tableau['0']."-".$tableau['1']."-".$tableau['2']."-".$tableau['3'].".googlebot.com";
if ($host=="crawl-".$tableau['0']."-".$tableau['1']."-".$tableau['2']."-".$tableau['3'].".googlebot.com")
{
// Google
$requete="INSERT robotip SET ip='$ip', ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',precedent='$precedent',

user_agent='$user_agent',x_forward='$x_forward'";
} elseif ($host=="msnbot-".$tableau['0']."-".$tableau['1']."-".$tableau['2']."-".$tableau['3'].".search.msn.com")
{ // msn
$requete="INSERT robotip SET ip='$ip',ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',precedent='$precedent',

user_agent='$user_agent',x_forward='$x_forward'";
}
elseif (strpos($host,".voilabot.orange.fr")!==false)
{
// voilabot
$requete="INSERT robotip SET ip='$ip',ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',precedent='$precedent',

user_agent='$user_agent',x_forward='$x_forward'";
}
elseif (($ipdecimal>=1123631104)AND($ipdecimal<=1123639295))
{
//Mediapartners-Google
$requete="INSERT robotip SET ip='$ip',ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',precedent='$precedent',

user_agent='$user_agent',x_forward='$x_forward'";
}
elseif (($ipdecimal>=2637627392)AND($ipdecimal<=2637692927))
{
//bing boot 157.55.0.0 - 157.55.255.255
$requete="INSERT robotip SET ip='$ip',ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',precedent='$precedent',

user_agent='$user_agent',x_forward='$x_forward'";
}
elseif (($ipdecimal>=3488735232)AND($ipdecimal<=3488739327))
{
//archive.org 207.241.224.0 - 207.241.239.255
$requete="INSERT robotip SET ip='$ip',ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',precedent='$precedent',

user_agent='$user_agent',x_forward='$x_forward'";
}
elseif (($ipdecimal>=1152679936)AND($ipdecimal<=1152712703))
{
//yahoo 68.180.128.0 - 68.180.255.255
$requete="INSERT robotip SET ip='$ip',ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',precedent='$precedent',

user_agent='$user_agent',x_forward='$x_forward'";
}
elseif (($ipdecimal>=1653080064)AND($ipdecimal<=1653342207))
{
//yahoo 98.136.0.0 - 98.139.255.255
$requete="INSERT robotip SET ip='$ip',ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',precedent='$precedent',

user_agent='$user_agent',x_forward='$x_forward'";
}
elseif ($ipdecimal==1255204963)
{
//dmoz 74.208.232.99
$requete="INSERT robotip SET ip='$ip',ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',

precedent='$precedent',

user_agent='$user_agent',x_forward='$x_forward'";
}
elseif ($ipdecimal==1255191758)
{
//dmoz 74.208.180.206
$requete="INSERT robotip SET ip='$ip',ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',

precedent='$precedent',user_agent='$user_agent',x_forward='$x_forward'";
}
elseif ($ipdecimal==3484204839)
{
//dmoz 207.172.191.39
$requete="INSERT robotip SET ip='$ip',ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',

precedent='$precedent',user_agent='$user_agent',x_forward='$x_forward'";
}
else
{
$requete="INSERT visiteurip SET ip='$ip',ipdecimal='$ipdecimal', host='$host',filename='$page',site='$site',precedent='$precedent',

user_agent='$user_agent',x_forward='$x_forward'";
}
$resultat=mysql_query($requete);
$page=STR_replace("/","",$page);
if ($page1=="index.php")
{
$page1="";
}

// fin suppression paramètres

date_default_timezone_set('Europe/Brussels');

// 1. vérification nb page
// on reprend les 4 dernières entrées et vérifie 3 valeurs différentes
include ('start.php');
$requete="select ip from visiteurip WHERE ip='$ip' order by uid DESC limit 0,4";
$resultat=mysql_query($requete);
$ligne=mysql_num_rows($resultat);
//$erreur=mysql_error();
// print($erreur);

$valeur=0;
while ($tableau=mysql_fetch_array($resultat))
{
// echo $tableau[ip]." -".$tableau[date_heure]."<br>";
if ($tableau['ip']==$ip)
{
$valeur=$valeur+1;
}
}

// On teste le nombre de pages différentes vues.

IF ($ligne>=3)
{
$valeur1=0;
$adresse=array();
$stamp=array();
// on récupère uniquement les fichier récupérés par la même IP
$requete="select * from visiteurip WHERE ip='$ip' order by uid DESC limit 0,3";
$resultat=mysql_query($requete);
while ($tableau=mysql_fetch_array($resultat))
{
// ECHO "pages vues";
$adresse[$valeur1]=$tableau['filename'];
// echo $tableau['filename'];
$stamp[$valeur1]= strtotime($tableau['date_heure']);
// echo $valeur1." - ".$adresse[$valeur1]." - ".$stamp[$valeur1]."<br>";
$valeur1=$valeur1+1;

}
if(count(array_unique($adresse)) == $valeur1)
{
// - toutes des pages différentes: copieurs? on analyse les délais entre les visites.

if ($stamp[0]-$stamp[2]<=10)
{
// 3 pages en moins de 10 secondes: on bloque, délais à réduire pour certains sites à 3-4 secondes.
$bloque="O";
//echo $bloque;
include ('start.php');
$requete="INSERT bloqueip SET ip='$ip',ipdecimal='$ipdecimal', ipdecimal_min='$ipdecimal', ipdecimal_max='$ipdecimal',bloque='$bloque'";
$resultat=mysql_query($requete);
// ------------ erreur 403
header("HTTP/1.1 403 Forbidden");
exit();
}
}
}

?>

Ici, il y a quelques exemples de possibilités sur des user_agents, pages précédentes spécifiques (redirection vers un site ou erreur 403). Les spécialistes verront que les bricolages de semalt.com sont redirigés vers un de ses concurrent (petite pointe d'humour personnelle). Une partie des blocages peut également être faite par .htaccess. Dans un précédant développement, je vérifiais également si c'était un serveur mais les box étaient également détectées. Quelques sites spécifiques sont considérés comme "normaux": dmoz, archive.org (qui ne permet pas l'indexation par Google)

Le script d'appel

Ce script doit être placé en tout début de code sur chaque page. Dans cet exemple, l'adresse réelle est site /config.php

<?php
$adresse_reel="/config.php";
$page=$_SERVER['REQUEST_URI'];
if ($page<>$adresse_reel)
{
// on interdit l'accès
include ('ip.php');
header("HTTP/1.1 403 Forbidden");
exit();
}
include ('ip.php');
?>

Remarque, la partie adresse_reel est à déclarer sur chaque page. Pour les cms (que je n'utilise pas), elle doit être récupérée à partir de la table contenu en automatique (attention à l'URL-rewriting). Un bricolage d'adresse bloqué est affiché dans la table visiteurip (on sait jamais) mais bloqué. Dans cette partie, vous avez toutes les possibilités comme déterminer l'adresse réelle en ajoutant l'adresse du site l'adresse réelle, vous pouvez utiliser "http://www.site.com/adresse_page", $page="http://www.site.com".$_SERVER['REQUEST_URI']: la commande conditionnelle if est inchangée.

<13.1. Le fichier htaccess 

Mettre en ligne un site > 3. Quelques base de javascript

Sur le sujet: Liste des balises META TAG - Bien placer son site dans les résultats de recherche, un beau site ... c'est bien, un site visité c'est mieux.

Mise en ligne: 20/06/2015.

Magasin Informatique YBET à Chiny

Le site YBET informatique à Chiny (info, se dépanner, ...)