Être notifié au passage du robot google sur son site

Google BotLe référencement est parmi les grands soucis qu’un webmaster ou blogueur peuvent avoir, A chaque fois qu’on rajoute du contenu, la question qui se pose est : Quand est ce que le robot de Google passera pour l’indexer ? Aujourd’hui j’ai eu l’idée de partager une petite astuce pour être alerté au passage de Google sur votre site!

En fait pour indexer un site, google possède plusieurs robots (spider/crawler), ce sont des programmes qui tournent en boucle en parcourant le web et enregistrent tous les contenus qu’ils trouvent sur leurs chemin! Il en existe plusieurs :

  • GoogleBot : c’est le robot qui indexe les pages de contenu
  • Googlebot-Image: celui qui indexe les images (images.google.com)
  • AdsBot-Google: le robot de Google Adsense
  • Mediapartners-Google: sert à indexer les sites et à proposer la publicité en conséquence dans le cadre d’une partenaria (exemple lycos)

Il est possible de détecter le passage de l’un de ces robots sur son site, l’idée est de faire un test sur la variable global $_SERVER[‘UserAgent’], qui contient le nom du navigateur qui a effectué la requête HTTP!

Voici un bout de code pour envoyer un mail à chaque passage de GoogleBot sur votre site :

[code lang=’php’]
if(!empty($_SERVER[‘HTTP_USER_AGENT’])
{
if(strpos($_SERVER[‘HTTP_USER_AGENT’], ‘googlebot’) !== false)
{
$webmastermail = ‘[email protected]’;
mail($webmastermail, ‘Alerte Googlebot’,”GoogleBot t’as rendu visite sur la page : ” . $_SERVER[‘REQUEST_URI’]);
}
}
[/code]

Et voilà, grâce à ce bout de code vous serai notifiés à chaque passage du robot Google sur votre site!

Parcontre ce n’est pas génial coté securité! Dans une requêtte HTTP l’entête HTTP_USER_AGENT est modifiable, du coup un utilisateur malveillant peut flooder votre boite mails avec un grand nombre de requêtes ayant UserAgent: Googlebot! La solution est de faire un lookup sur l’adresse IP envoyant la requête et résoudre le nom de domaine avec la fonction gethostbyaddr, si le nom de la machine ne correspond pas à *.googlebot.com pas d’envoi d’email ;)

[code lang=’php’]
if(!empty($_SERVER[‘HTTP_USER_AGENT’])
{
if(strpos($_SERVER[‘HTTP_USER_AGENT’], ‘googlebot’) !== false)
{
if(preg_match(‘#.*?\.googlebot\.com$#’,gethostbyaddr($_SERVER[‘REMOTE_ADDR’])))
{
$webmastermail = ‘[email protected]’;
mail($webmastermail, ‘Alerte Googlebot’,”GoogleBot t’as rendu visite sur la page : ” . $_SERVER[‘REQUEST_URI’]);
}
else
{
// on peux bannir l’adresse en la rajoutant au fichier .htaccess
/* if(is_writable(‘.htaccess’))
{
$h = fopen(‘.htaccess’,’a+’);
fwrite($h,”\nDeny from: “.$_SERVER[‘REMOTE_ADDR’]);
fclose($h);
}
*/
}
}
}
[/code]

A savoir que bannir l’utilisateur si le hostname ne correspond pas n’est pas une très bonne idée vu que google peut changer de domaine (*.googlebot.com), par contre ça vous évitera de recevoir un joli paquet d’emails, j’ai commenté cette partie du code pour éviter de bannir google si jamais *.googlebot.com change ;)

J’espère que cet astuce vous sera utile!

Bonne nuit!

[Tutoriel] SQL Injection – Les classiques (partie1)

sql_imgHello,
Aujourd’hui je vous parlerai d’un vecteur d’attaque très répondu sur internet, c’est SQL Injection, le sujet est très riche, j’ai donc décidé de le répartir en trois parties:

J’ai également publié un billet bonus parlant des techniques d’évasion des filtres

Dans ce billet, j’expliquerai le concept d’une Injection SQL basique, les différentes formes sous lesquelles elle peut se présenter dans une application WEB, illustrées par des exemples concrets, ainsi que des solutions pour sécuriser son code et prévoir ce genre d’attaques!

Comme vous le savez tous, SQL (Structured Query language), est un langage de bases de données qui constitue le cœur des applications WEB qui interagissent avec un SGBD, sachant que le concept d’une Injection SQL est commun pour tous les types de SGBD (avec quelques petites variations), dans toute la série de ces tutoriaux, je vais considérer qu’on travaille sur une base de données MySQL qui tourne sur un serveur LAMP!

Alors c’est parti =)

SQL Injection, c’est quoi ?

SQL Injection est parmi les vecteurs d’attaques les plus connus sur la toile!, son principe est de modifier une requête SQL grâce à un champ mal filtré dans le but d’exécuter une requête non prévue par l’application, l’exploitation d’une injection SQL peut avoir des conséquences désastreuses sur un site, elle peut permettre à un attaquant de :

  • Bypasser une authentification
  • Lire des données sensibles depuis les tables mySQL
  • Injecter le nom et le schéma de la base de données
  • Lire et écrire dans le système de fichier et potentiellement exécuter du code PHP

Comment repérer une injection SQL?

Une Injection SQL est souvent repérée par un attaquant grâce aux messages d’erreurs, le test est assez facile à faire, il suffit d’insérer un caractère spéciale (un signle quote “‘” le plus souvent), ou modifier le type d’une variable utilisée dans une requête SQL, si la variable est mal filtrée l’exécution de la requête est interrompue et il y a de fortes chances que cette dernière est faillible à une Injection

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near

Et oui! c’est ça, merci mysql_error =)

Et si on passe aux exemples?

Assez de blabla, là on passe aux exemples, et on commence par l’un des plus classiques :

Bypasser une identification:

Stanislas: un développeur en herbe a conçu un formulaire d’identification, qui permet de poster le nom d’utilisateur et le mot de passe dans une page PHP, cette dernière vérifie si c’est les bons et affiche un message selon le résultat:

Code :
[code lang=’php’]
// page processlogin.php
$username = $_POST[‘username’];
$password = $_POST[‘password’];
$sql = mysql_query(“SELECT * FROM users WHERE username = ‘$username’ AND password = ‘$password'”) or die(mysql_error());
if(mysql_num_rows($sql) == 1)
{
echo “Bienvenue $username dans votre espace membre!”;
}
else
{
echo “Nom d’utilisateur et/ou mot de passe incorrecte”;
}
[/code]

Maintenant imaginons qu’un attaquant se connecte avec comme login : admin’–, la requête devient :

SELECT * FROM users WHERE username = ‘admin’–‘ AND password = ‘$password’

La requête SQL va aboutir, le single quote permettra de fermer le délimiteur de la chaine admin et les deux tirées servent à mettre le reste de la requête en commentaire, du coup la vérification du mot de passe sera ignorée ;) , Bienvenue admin dans votre espace membre!

C’est juste un exemple! l’attaque peut se présenter différemment selon la requête SQL :

Exemple 2:
[code lang=’php’]
//…
$sql = mysql_query(“SELECT * FROM users WHERE ( username=’$username’ AND password = ‘$password’ )”);
[/code]

Dans ce cas, pour bypasser l’identification il y a plusieurs possibilités, l’une est d’utiliser comme login: admin’)–
ou encore, comme login : admin’) or (‘a’=’a, le principe est de toujours forcer la requête à retourner true :)

Injecter des données depuis une table

On dit souvent que l’union fait la force! c’est le cas pour les injections SQL car là on arrive aux choses sérieuses!

La commande UNION, existe depuis MySQL 4.0 et permet de combiner le résultat de plusieurs requêtes SELECT en une seule. Pour l’UNION, il est important que les champs des différents SELECT aient le même nombre et le même type!

Prenant l’exemple d’un petit forum, on considère une page profile.php qui affiche le profil d’un utilisateur donné à partir de son ID récupéré par $_GET

Code :

[code lang=’php’]
mysql_connect(“localhost”,”root”,””);
mysql_select_db(“test”);
$user_id = $_GET[‘id’];
$sql = mysql_query(“SELECT usernamen, nom, prenom, email FROM users WHERE user_id = $user_id”) or die(mysql_error());
if(mysql_num_rows($sql) > 0)
{
$data = mysql_fetch_object($sql);
echo ”

Profile de “.$data->username.”

Nom d’utilisateur : “.$data->username.”

Nom et prénom : “.$data->nom.” ” .$data->prenom .”

Adresse email : “.$data->email.”

“;
}
[/code]

Sans connaitre le code qui s’exécute derrière un attaquant peut détecter la présence d’une injection sql en essayant d’interrompre la requête en accèdent à la page : profile.php?id=1′, le fameux message d’erreur s’affiche, l’attaquant passe à l’étape suivante, qui est l’identification de nombre des champs utilisés dans le SELECT

La technique la plus courante est l’utilisation de la clause “ORDER BY”, en incrémentant l’indice petit à petit jusqu’à ce que la page affiche une erreur

  • profile.php?id=1 order by 1 [OK]
  • profile.php?id=2 order by 2 [OK]
  • profile.php?id=3 order by 3 [OK]
  • profile.php?id=4 order by 4 [OK]
  • proile.php?id=5 order by 5 [ERREUR]

A ce stade là, l’attaquant peut savoir que la requête contient 4 champs dans le SELECT, et peut donc utiliser la clause UNION pour injecter des données!

profile.php?id=-1 UNION SELECT 1,2,3,4–

là on peut bien voir les chiffres s’afficher au lieu des données vu que l’id -1 n’existe pas dans la base, du coup les champs sélectionné dans l’UNOIN seront retourné (1,2,3,4), à la place de ces derniers l’attaquant peut sélectionner des données de n’importe quelle table sur laquelle l’utilisateur sql courant a les droits

Exemple :

profile.php?id=-2 UNION SELECT version(), user(), password, null FROM users
profile.php?id=-2 UNION SELECT host, user, password, database() FROM mysql.user

Il est facile pour un attaquant de deviner le nom des tables, d’ailleurs il existe des listes de tables sensibles susceptibles d’exister sur une base de données genre (login, users, auth, membres..), et depuis mysql 5 il est possible d’injecter les noms des tables à partir de la base information_schema! je reviendrai dans le billet de cette série (SQL Injection avancée) avec plus de détails sur cette partie là!

Il est également possible d’injecter des données depuis les autres bases sur-lesquelles l’utilisateur mysql courant a des droits!

Comment se protéger?

Maintenant que vous avez conscience du danger qu’une injection SQL classique pourrait engendrer lorsqu’elle est exploitée voici les bonnes pratiques pour sécuriser son application :

Pour notre cas par exemple : la solution est de filtrer l’input $_GET[‘id’] on conservant que la partie entière de sa valeur, pour ce faire :
[code lang=’php’]
$user_id = intval($_GET[‘id’]);
[/code]

et voilà le tour est joué :) , s’il s’agissait d’un nombre à virgule flottante on utilisera floatval() et ainsi de suite..

Pour les chaines de caractères, pensez toujours à utiliser mysql_real_escape_string, cette fonction permet de filtrer tous les caractères spéciaux et vous facilitera la vie! Et si vous avez le malheur de ne pas les utiliser dans vos requêtes, alors c’est bien le moment ;)

Donc voilà les classiques pour les injections SQL! Dans le prochain billet, on passera à la vitesse supérieur! J’exposerai des méthodes d’exploitation plus avancées, des erreurs à ne pas commettre ainsi que des solutions pour prévenir à ce genre d’attaques!

Injection de code dans une expressions rationnelle (REGEX Injection)

Regular expression injectionSalut à tous!

Aujourd’hui je vous parlerai de la sécurité des expressions régulières, appelées aussi expressions rationnelles, ou tout simplement REGEX pour les intimes! Si vous en usé dans vos codes, ce billet est pour vous!

Les expressions rationnelles permettent de manipuler une chaine de caractère de façon très puissante, elles sont souvent utilisées pour la validation des données, le parsing du bbcode dans les forums, également dans les commandes unix comme grep et sed, mais ce n’est pas notre sujet aujourd’hui!

Où est le problème?

Dans une expression rationnelle, il est possible d’utiliser un modificateur “e” qui permet d’évaluer le code contenu dans la chaine de remplacement, donc exécuter du code php!

Dans le language Perl ainsi que dans tous les technologies qui utilisent la librairie PCRE (Perl-compatible regular expressions), y compris PHP, ces derniers supportent l’utilisation de ce modificateur, un attaquant malveillant peut injecter du code si l’entrée n’est pas correctement filtrée!

Exemple :

Voici un code qui parse une chaine de caractère et remplace tous ce qui existe entre [b] et [/b] par <strong>CHAINE</strong>, on le mettant en majuscule!

[code lang=’php’]
$nom = “toto”;
$chaine = “Hello my name is [b]”.$nom.”[/b]”;
$pattern = “#\[b\](.*)\[/b\]#e” ;
$replacement = “‘‘.strtoupper(‘$1′).’‘”;
$display = preg_replace($pattern , $replacement, $chaine);
echo $display ;
[/code]

Que se passera t’il si toto s’appelle ainsi :

  • ‘.phpinfo().’
  • ‘.exec(\$_GET[cmd]).’
  • ‘.include($_GET[backdoor]).’

Dans toutes les versions PHP < 5.0.5 La chaine de remplacement deviendra : <strong>’.strtoupper(‘\\1‘.phpinfo().’‘).'”</strong> est le code php sera exécuté ! du coup, un attaquant peut injecter un code malveillant !

Comment se protéger?

Si jamais vous êtes amenés à utiliser des expressions rationnelles avec le modificateur “e”, pensez à filtrer vos variables en utilisant la fonction escapeshellcmd, d’où notre code deviendra :

[code lang=’php’]
$nom = “simo.’phpinfo().'”; // test d’injection
$chaine = “Hello my name is [b]”.$nom.”[/b]”;
$pattern = “#\[b\](.*)\[/b\]#e” ;
$replacement = “‘‘.strtoupper(escapeshellcmd(‘$1′)).’‘”;
$display = preg_replace($pattern , $replacement, $chaine);
echo $display ;
[/code]

Sinon Le plus simple est d’utiliser une version récente de PHP > 5.0.5 est le tour est joué ;)

Javascript: comment récupérer le texte sélectionné

En javascript, parfois on a besoin de récupérer le texte sélectionné par le client, c’est souvent utilisé si vous développez votre propre éditeur wysiwig afin de mettre un texte en gras ou placer un lien hypertexte autour de votre sélection!

Bref voici une fonction cross-browser qui vous permet cela!

Code :

[code lang=’javascript’]
getSelectedText = function(){
selectedText = ”;
// Gecko, Webkit
if (window.getSelection) {
selectedText = window.getSelection();
}
// Si IE
else if (document.selection) {
selectedText = document.selection.createRange().text;
}
return selectedText ;
}
[/code]

Et si on fait un test !

Sélectionnez un texte quelconque dans le blog, et cliquez sur le bouton ci dessous!

voilà c’est aussi simple que ça!

CSP un nouveau système de protéction contre les XSS implementé par Firefox

MozillaContent Security Policy, baptisé CSP, est une nouvelle technologie créée par la fondation Mozilla dans le but de se protéger contre les attaques XSS!
Dans les trois dernière années, l’exploitation des attaques XSS et CSRF Injection a connu une très forte croissance, on a vu pas mal d’incidents et des hackages de sites populaires et de grands comptes comme facebook , ImageShack, DomainTools, Godady…, les ingénieurs de mozilla security team ont pensé à une solution et nous ont inventé CSP!

CSP, c’est quoi au juste?

En principe, les attaques XSS sont possibles car toutes les données chargées depuis un serveur http sont interprétées par le navigateur avec les droits que le client possède, le code JavaScript et tout le contenu chargé (y compris les scripts externes) sont combinés dans un même conteste de sécurité (Policy) et permettent l’accès à la totalité du DOM. Content Security Policy nous apporte un mécanisme pour indiquer explicitement au navigateur quel contenu est légitime, de cette façon le navigateur pourra interrompre l’exécution et restreindre l’accès au DOM de tout contenu non autorisé et sans perdre des fonctionnalités dans le site!

CSP est destiné aux web designers et administrateurs système afin de designer la façon avec laquelle les données doivent interagir avec leurs sites, son implémentation permettra la détection des attaques de type XSS et injection de code HTML et minimiser les risques d’une potentielle exploitation d’un de ces deux vecteurs d’attaque

Comment ça marche ?

Le principe de CSP est d’appliquer un ensemble de restrictions sur l’exécution des scripts et les autoriser seulement à partir d’une liste blanche créée par le webmaster, ainsi toute exécution de script ou de code chargé depuis un site non figurant dans cette liste sera bloquée. On pourra par exemple autoriser seulement les scripts provenant de Google API, et Youtube et restreindre l’accès à tout autre domaine externe!

Voici une liste de quelques actions bloquées par CSP:

  • les balise <script>
  • les URI javascript:fonction()
  • les évènements placés dans les attribut (<a onclick=”return foo()”>)
  • les fonctions avec le constructeur var f = new Function(“code malveillant…”)
  • data URI genre : data:text/plain;base64,ZXZpbGNvZGU=

Une liste complète de restrictions est disponible sur le wiki officiel de mozilla

Comment activer CSP sur son site?

Pour activer cette protection sur votre site, il vous suffit d’ajouter X-Content-Security-Policy dans l’entête HTTP de vos pages, voici un exemple simple pour autoriser l’exécution des scripts seulement depuis le même domaine :

[code lang=’html’]X-Content-Security-Policy: allow ‘self'[/code]

Un exemple pour autoriser le chargement des images depuis tous les domaines et les scripts seulement depuis api.google.com:

[code lang=’html’]X-Content-Security-Policy: allow ‘self’; img-src *; \
script-src api.google.com
[/code]

Notifications

L’avantage de CSP c’est qu’il possède un mécanisme de notification permettant de notifier le webmaster lors de la violation d’une règle, la notification est sous forme d’un rapport que le navigateur envoie via une requête HTTP POST formatée en XML, et contient les entêtes HTTP de la requête effectuée par le client, l’url bloqué, la directive violée et le site de provenance! de cette façon administrateur du site pourra détecter les défaillances et d’éventuels problèmes de sécurité qui peuvent menacer son site!

Voici le schéma d’une requête de notification :

[code lang=’xml’]













[/code]

Exemple de rapport lors de l’appellation d’un script depuis un domaine non autorisé (attacker.ltd)

[code lang=’xml’]

GET /page.php HTTP/1.1

http://attacker.ltd/evilscript.js
script-src self
allow none; script-src *, allow self; script-src self

[/code]

On peut placer l’entête dans une balise méta dans le <head>:

[code lang=’html’]

[/code]

en PHP

[code lang=’php’]
Header(“X-Content-Security-Policy: listedesrestrictions”);
[/code]

CSP est une très bonne initiative pour luter contre les attaques XSS, il est nativement implémenté dans le navigateur Firefox à partir de la version 3, c’est principalement conçu pour nous assurer une meilleure sécurité, tout de même il ne faut pas penser que c’est la fin des XSS! il y aura sans doute des méthodes pour le contourner, sinon je trouve que c’est bien pensé de la part des équipes Mozilla, c’est du beau boulot!

Viva Firefox ;)