Projet sfAntiBruteForcePlugin

7 gravatar Par Grégoire Marchal - 11/12/2010

Récemment j'ai créé une petite application web pour jouer un peu avec les API de twitter, qui est sécurisée par un classique login / mot de passe : sécurité basique. Je me suis rapidement dit qu'il faudrait ajouter une sécurité pour parer aux attaques de type "brute force". Pour rappel, ce type d'attaque consiste à tenter un maximum de couples login / mot de passe sur un formulaire en espérant trouver des identifiants qui fonctionnent (plus d'info). J'ai rapidement cherché quelques informations à ce sujet et espéré trouvé un plugin symfony tout fait (on peut espérer non ?). Résultat : pas de plugin, mais quelques informations intéressantes qui m'ont donné envie de me lancer dans le développement du fameux plugin que je cherchais ! Je vais donc recenser ces informations ici, faire une sorte de cahier des charges collaboratif pour mon plugin, et j'espère bien que vous allez m'y aider !

La plupart des informations intéressantes que j'ai récoltées proviennent de ce tutoriel : un anti brute-force léger et rapide.

Le principe : empêcher un utilisateur et surtout un robot de tenter une infinité de couples login / mot de passe sur une page d'authentification donnée. Pour cela, on doit compter les tentatives erronées des utilisateurs, et les empêcher à partir d'un certain seuil de tentatives par unité de temps. Voici les questions qui en découlent.

Sur quoi se baser pour compter les tentatives ?

Sur l'IP du client ? Mauvaise idée, cette donnée n'est pas fiable, la plupart des hackers sauront la modifier et pourront donc faire une infinité de tentatives.

Sur les sessions ? Non plus, il suffit d'effacer le cookie et c'est reparti pour d'autres tentatives...

Sur le login utilisé pour l'authentification ? Ce n'est pas une solution parfaite, mais c'est la meilleure que j'ai trouvé à ce jour. L'inconvénient principal est que n'importe qui peut bloquer le compte de quelqu'un s'il connait son login...

Si vous avez d'autres idées, je suis preneur !

Comment stocker le nombre de tentatives effectuées ?

En base de données ? Ca semble être la solution la plus logique. Néanmoins, certains projets ne fonctionnent pas avec une base de données (et c'est mon cas ici !). Ce serait un peu intrusif de devoir créer une base pour ça, de charger un ORM etc.

Dans des fichiers ? C'est la solution qu'a choisi l'article ci-dessus. Niveau rapidité, charge etc., il faudrait faire un comparatif avec l'utilisation d'un ORM pour savoir qui est le meilleur. Cette solution est moins envahissante dans la mesure où elle fonctionnerait sur tous les projets symfony (à ma connaissance).

Si vous avez d'autres idées...

Où intervenir au niveau du code symfony ?

A la base, j'avais pensé qu'il faudrait faire un filtre pour contrôler les accès en amont dans l'application. Le problème est que, si je pars sur la solution d'utiliser le login pour compter les tentatives, j'ai besoin de ce login pour incrémenter son compteur de tentatives en cas d'échec. J'ai donc également besoin de savoir si la tentative d'autentification est un échec ou non. Pour cela, j'ai donc besoin d'internvenir au niveau du contrôleur, dans l'action qui gère l'authentification. J'imagine que le développeur devra ajouter un appel de ce genre lorsqu'une tentative d'authentification échouera :

sfAntiBruteForceManager::notifyFailedAuthentication($identifier);

Cette méthode aura pour but d'incrémenter le compteur d'échec pour cet utilisateur.

Il faudrait également, avant la tentative d'authentification, vérifier que l'utilisateur qui s'apprête à s'authentifier a le droit de le faire :

if (sfAntiBruteForceManager::canTryAuthentication($identifier))
{
  // ...
}

Faut-il s'intégrer au plugin sfGuard ?

Dans un second temps peut-être, on va pas mettre la charrue avant les bœufs ! Mais bon, à creuser.

Voilà pour les premières pistes pour la réalisation de ce petit plugin qui me semblerait très utile pour tout développeur sensible à la sécurité de son application (aka tout bon développeur !). J'attends vos remarques / suggestions / idées avec impatience !

PS : suivez les évolutions sur la page officielle de sfAntiBruteForcePlugin.

Retour à l'accueil

Commentaires (7)

gravatar Par Alexandre PAIXAO, le 11/12/2010 à 17:28
Sur quoi se baser pour compter les tentatives ?
-> Sur le nombre d’échecs lié à un login ca me semble correct, c’est ce que j’ai fait récemment. Mais à y repenser, il y a peut être plus efficace : croiser plusieurs critères.
Je m’explique : si un login a essuyé plusieurs échecs d’affilé il y a des chances que ce soit une tentative de brute force, mais si les tentatives sont espacées de quelques secondes c’est plus suspect que si elles sont espacées de quelques minutes. De même, si une IP n’a jamais réussi à se connecter une seule fois (cas d’un proxy qui n’est pas utilisé par des utilisateurs normaux) ca peut constituer un facteur agravant.
On compile le tout sous forme d’un score et on prend la décision qui s’impose !

Comment stocker le nombre de tentatives effectuées ?
Une base de donnée NoSQL ? Il me semble que MongoDB s’appuie sur un fichier, c’est très performant. Ya SQLLite aussi.

Où intervenir au niveau du code symfony ?
Faut-il s’intégrer au plugin sfGuard ?
Je suis d’accord avec toi sur ces deux points
gravatar Par Extaze, le 11/12/2010 à 19:46
Hum sinon ya sleep(1) pour stopper le PHP une seconde, a mettre sur la page de login. C’est pas trop visible par le visiteur, mais pour le robot, ca allonge tellement le temps de bruteforce que voilà …
gravatar Par Grégoire Marchal, le 11/12/2010 à 22:01
@Alexandre : une règle de calcul de ce genre ça serait pas mal en effet, mais ça m’effraie une peu à vrai dire ! C’est le genre de truc compliqué à équilibrer et mettre au point. Mais je garde ça dans le coin de la tête pour la v2 !

Pour le stockage, il faut vraiment un truc léger et avec le minimum de dépendance. J’avoue que j’ai jamais regardé NoSQL et MongoDB, je me pencherai là dessus. Merci pour tes remarques :)

@Extaze : cette solution est certes simple, mais pas assez efficace à mon goût. Mais merci d’avoir proposé !
gravatar Par tight, le 12/12/2010 à 23:39
Pour ton appli twitter, pourquoi tu ne passes pas par oauth ? (il me semblait que l’authentif basique était déjà abandonnée..)

Sinon, pour le problème de brute force en général, tu peux aussi te baser sur les idées anti-spam. Tout n’est pas à prendre (j’ai jamais encore vu de captcha sur un formulaire d’identif), mais y’a de bonnes idées (si le gars met à chaque fois moins de x millisecondes pour saisir identifiant / mot de passe, c’est que c’est probablement pas un mec derrière son clavier)

@Extaze : très mauvaise idée le sleep : c’est très facile de faire une attaque DoS là dessus (toutes les connexions bloquées sur le sleep)
gravatar Par Grégoire Marchal, le 13/12/2010 à 10:22
J’utilise bien oauth (effectivement c’est la seule manière de faire), mais pour l’instant j’ai stocké mon token et mon secret en dur en conf, parce que j’ai pas encore testé si le process d’authentification complet fonctionne malgré websense :).

Sur twitter on m’a suggéré de mettre un captcha uniquement si on a atteint la limite de mauvaises authent, c’est pas bête je trouve. Mais en fait, je pense que ça sera à la charge du développeur qui utilise le plugin de décider ce qu’il fait une fois que la limite est atteinte : blocage ou captcha, ou autre chose…

Idéalement il faudrait même que le plugin laisse le choix au développeur pour la manière de stocker les compteurs : fichier ou base de données, ou autre…
gravatar Par Grégoire Marchal, le 13/12/2010 à 23:29
Bon, j’étais motivé tout à l’heure, j’ai packagé une petite beta :)
http://www.symfony-project.org/plugins/sfAntiBruteForcePlugin
gravatar Par tight, le 14/12/2010 à 22:59
> Idéalement il faudrait même que le plugin laisse le choix au développeur pour la manière de stocker les
> compteurs : fichier ou base de données, ou autre…

+1

Commenter