Steve TENZA
Intervient pour votre site internet
Facebook Me contacter Cookie
Télécharger
Noter:
Ajouté/Modifié le 2025-01-12
Visionné 4430 fois

Bloquer les faux partages Facebook venant de facebookexternalhit

Description

Il s'agit pour l'attaquant d'une approche pour spammer n'importe quel site en utilisant l'API Facebook de partage de liens, et même si cet accès arrive sur votre site, il n'y a aucun enregistrement dans la base de données de Facebook quand on vérifie avec leur outil Facebook Share Debugger : https://developers.facebook.com/tools/debug.

Normalement, si elle est partagée elle doit être enregistrée dans le débogueur et mise en cache par Facebook, mais cet accès ne l'est pas et donne aucun résultat : "This URL hasn't been shared on Facebook before.".

Voyant des logs GET arrivant de l'agent utilisateur "facebookexternalhit", je me dis "chouette, on partage beaucoup mon site !", en réalité, personne (haha) j'ai voulu voir qui partageait ces pages en masse via le débugueur Facebook et il y avait rien. Pour information, ce nombre était d'environ 800 faux partages/jour (mais certains peuvent avoir des milliers de partages en quelques minutes seulement, c'est une faille exploitée pour faire des dénis de service DDoS et appréciée, car l'attaquant se cache derrière l'identité de FB).

J'ai donc cherché à savoir d'où venait ces fausses visites partagées en recherchant des termes comme "fake facebookexternalhit" ou "flood facebook sharing URL" pour avoir des pistes, je suis tombé sur quelques sujets intéressants, on peut s'apercevoir que FB est au courant, mais ne fait actuellement rien en ignorant ce problème (FB pourrait envoyer une entête spéciale quand ce sont eux qui crawl la page et enlever l'entête quand les crawl sont faits à partir de leur API, ça pourrait limiter les dégâts).

Comment faire pour bloquer ces faux hits Facebook ?

On ne va quand même pas interdire le partage de notre site sur ce réseau social, FB est la source numéro 1 de nos partage de liens, c'est inconcevable pour la plupart d'entre nous.

Cherchant une solution, en vain, j'ai finalement réalisé un script PHP qui permet de déterminer si c'est un vrai ou faux partage, car d'après cette info intéressante de Facebook, son robot envoi les entêtes suivantes quand il vient crawler nos pages :

HTTP_ACCEPT_ENCODING et HTTP_RANGE


Et c'est vrai, mais pas tout le temps, et c'est là où ça se complique, lors de mes tests de partage de liens pour enregistrer les entêtes et les comparer aux fausses, FB a crawler 4 fois la même page en 2 secondes environ, les deux premiers crawl contenait les entêtes HTTP_ACCEPT_ENCODING et HTTP_RANGE, les autres, non, il faut donc faire une vérification des crawls qui suivent le premier et calculer si les crawl suivant se font de suite après (on va compter 5 secondes d'intervalle entre le premier crawl avec les entêtes requises et les suivantes sans entêtes requises pour contrer les éventuels ralentissements de notre site au moment du crawl. EDIT 2025 : après avoir testé mon script pendant 6 mois, je vous conseil de mettre 20 secondes pour éviter tout problème de partage légitime non pris en compte, qui pourrait vous faire perdre en visibilité sur le réseau social.)

Voilà le code PHP pour bloquer les faux partages Facebook

Pour vous aider à comprendre le fonctionnement, vous trouverez des commentaires à chaque étape. Si vous avez des questions, postez-la plus bas. 💬

Télécharger le script complet
(Téléchargé 151 fois)


<?php

//CODE TEST :
//ENLEVEZ/COMMENTEZ LE CODE QUI SUIT EN MODE PRODUCTION
//pour tester, augmentez $TEMPS_ENTRE_REELS_CRAWL à 30 secondes, le temps que vous puissiez voir les message d'erreurs/succès

//mettre d'abord true pour un vrai crawl FB (il se loguera) puis false pour un faux crawl
$vrai_crawl = true;

if($vrai_crawl){

$_SERVER = [
'HTTP_USER_AGENT' => 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)',
'HTTP_ACCEPT_ENCODING' => 'deflate, gzip',
'HTTP_RANGE' => 'oui',//'oui' juste pour indiquer que HTTP_RANGE existe
'REQUEST_URI' => 'page.html',
];

}else{

$_SERVER = [
'HTTP_USER_AGENT' => 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)',
'REQUEST_URI' => 'page.html',
];

}
//FIN CODE TEST.


class Block_fake_fb_hits {

//429 (Too Many Requests) indique à l'utilisateur qu'il a envoyé trop de requêtes en un temps donné
protected $CODE_ENTETE_HTTP = 429;

protected $DOSSIER_LOGS = 'logs_fb_hits/verifications';

protected $SAUVER_LOGS = true;

protected $DOSSIER_LOGS_GLOBAUX = 'logs_fb_hits/logs_globaux';

//[date] sera remplacé par la date du jour pour ne pas avoir un fichier trop volumineux, chaque jour un nouveau fichier est créé
protected $FICHIER_LOGS_GLOBAUX = '[date].log';

//création des fichiers logs globaux chaque heure, si false, crée un seul fichier par jour
//mettre true si ya beaucoup de faux crawl pour dispatcher les logs en plusieurs fichiers
protected $INCLURE_HEURE_DANS_NOM_LOG = false;

//séparateur des infos logs dans les fichiers globaux, l'utilisation '"[espace][tiret]"' est nécessaire pour ne pas rentrer en conflit avec REQUEST_URI, une URL n'aura jamais un espace et un guillemet n'ont plus "
protected $SEPARATEUR = '" -"';

//secondes entre le bon hit et les suivants que FB peut envoyer sans les entêtes
protected $TEMPS_ENTRE_REELS_CRAWL = 5;

//init
protected $FICHIER_VERIFICATION;
protected $REQUEST_URI;
protected $HTTP_HOST;
protected $HTTP_USER_AGENT;
protected $REMOTE_ADDR;

//suivant là où est inclut Block_fake_fb_hits.php (à configurer dans le constructeur)
protected $_DIRNAME;


public function __construct(){

$this->REQUEST_URI = $_SERVER['REQUEST_URI'] ?? '';
$this->HTTP_HOST = $_SERVER['HTTP_HOST'] ?? '';
$this->HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT'] ?? '';
$this->REMOTE_ADDR = $_SERVER['REMOTE_ADDR'] ?? '';

//crée un fichier de vérification uniquement pour la page parcourue
$this->FICHIER_VERIFICATION = 'fb-' . preg_replace("#[^a-z0-9-_]+#i", '-', $this->REQUEST_URI) . '.hit';

//"__DIR__, 1" pour remonter d'un dossier, "__DIR__, 2" de deux, etc
// $this->_DIRNAME = dirname(__DIR__, 2);
$this->_DIRNAME = __DIR__;

}

public function verifier(){

//un vrai crawl FB contient les entêtes HTTP_ACCEPT_ENCODING et HTTP_RANGE (https://developers.facebook.com/docs/sharing/webmasters/crawler/)

$est_fb_hit =
strstr($this->HTTP_USER_AGENT, 'facebookexternalhit') !== false
||
strstr($this->HTTP_USER_AGENT, 'facebookcatalog') !== false;

if(!$est_fb_hit)
return true;

$bon_hit = isset($_SERVER['HTTP_ACCEPT_ENCODING'], $_SERVER['HTTP_RANGE'])
&& $_SERVER['HTTP_ACCEPT_ENCODING'] == 'deflate, gzip';


$chemin = $this->_DIRNAME . '/' . $this->DOSSIER_LOGS . '/' . $this->FICHIER_VERIFICATION;

if($bon_hit){

//on met à jour son dernier passage
file_put_contents($chemin, time(), LOCK_EX);

//sauvegarde le log si on veut voir
$this->sauver_log(true);

return true;

}else{

if(!file_exists($chemin)){

$this->bloquer();

return false;

}

$access_line = file_get_contents($chemin);

//vérifie si ya eu un réel crawl ya moins de 5 secondes
if((int) $access_line >= time() - $this->TEMPS_ENTRE_REELS_CRAWL)
return true;

$this->bloquer();

return false;

}
}

private function bloquer(){

//sauvegarde le log si on veut voir
$this->sauver_log(false);

http_response_code($this->CODE_ENTETE_HTTP);


}

private function sauver_log($vrai_hit){

if(!$this->SAUVER_LOGS)
return;

$new_log = [];

$new_log[] = date('Y-m-d H:i:s');
$new_log[] = $this->REQUEST_URI;
$new_log[] = $this->HTTP_HOST;
$new_log[] = $this->REMOTE_ADDR;
$new_log[] = $this->HTTP_USER_AGENT;

$new_log = implode($this->SEPARATEUR, $new_log);


$date_fichier_log = $this->INCLURE_HEURE_DANS_NOM_LOG ? date('Y-m-d-H') : date('Y-m-d');
$fichier_log = str_replace('[date]', $date_fichier_log, $this->FICHIER_LOGS_GLOBAUX);
$fichier_log = ($vrai_hit ? 'vrais' : 'faux') . '/' . $fichier_log;

$chemin_logs = $this->_DIRNAME . '/' . $this->DOSSIER_LOGS_GLOBAUX . '/' . $fichier_log;

file_put_contents($chemin_logs, $new_log . "\n", FILE_APPEND | LOCK_EX);

}
}

if((new Block_fake_fb_hits())->verifier() === false){

//message d'erreur ici
echo "<h1 style='color:red'>FAUX CRAWL FACEBOOK</h1>";
exit;

}

//contenu de la page ici
echo "<h1 style='color:green'>REEL CRAWL FACEBOOK / HUMAIN</h1>";


_ /logs_fb_hits
|_ /verifications
|_ /logs_globaux
|_ /faux
|_ /vrais
🚀 Simple, rapide et efficace pour suivre le trafic de votre site web : C2stats pour savoir qui vient sur votre site, où sont partagées les pages de votre site, le nombre de visiteurs sur mobiles...

J'espère que ce script gratuit vous est utile.
Pour soutenir mon travail, un simple don ou mettre une note est grandement apprécié.
Votre réussite en ligne commence ici

Vous cherchez à pousser encore plus loin vos idées ou à les concrétiser avec un site internet sur mesure ? Je suis là pour vous aider ! Mon expérience en développement web est à votre disposition.

Que ce soit la création de votre site web pro ou l'apport de fonctionnalités avancées à votre projet, contactez-moi pour en discuter et avoir un devis gratuit personnalisé.

Mon objectif est de vous offrir des solutions sur mesure qui répondent à vos besoins, et votre vision associée à mon expertise donnera vie à votre projet web parfait. Contactez-moi aujourd'hui, je réponds en général en moins d'une heure :

Demander un devis
Réponse rapide !

Vous recherchez un script précis ?

Dites-moi ce dont vous avez besoin, je peux développer le script demandé et vous envoyer un mail dès qu'il est dispo !

🔔 Vous pouvez laisser votre mail pour recevoir les nouveaux scripts. Pas de pub, pas de tracas. Vous êtes libre de le supprimer à tout moment.

Je prends en compte toutes les demandes. Les idées les plus populaires passent en priorité et seront publiées dès qu'elles seront prêtes. 2869 demandes reçues.

Si vous avez un projet en tête, je vous suggère de me contacter directement pour en discuter.

Commentaires

Ajouter un commentaire

Commenter
Pseudo/Nom
Email
Message
Captcha
memo1
Commenter
Ajoutez un commentaire, soyez le premier !

Retour à la liste des scripts

Un site à créer ?
Contactez-moi