Execution de code PHP sécurisée

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Execution de code PHP sécurisée

par Genova » 08 juin 2007, 15:23

A partir du moment où tu autorises la création de fonctions, les for, foreach et while c'est la porte ouverte à tous les problèmes. Va falloir rudement faire confiance à tes membres hein ... Comment créer des boucles infinies ?
while (1) // N'importe quel nombre marche ...
while (true)
$toto = 42;
$titi = 42;
while ($titi == $toto)
function recurs()
{
   recurs();
}
recurs();
for ($i = 0; $i > -1; $i++)
{

}
etc etc ...

Il y a trop de moyens de faire n'importe quoi, même avec les instructions les plus simples.

A mon avis : je sais pas pourquoi tu as besoin que tes utilisateurs utilisent du PHP, mais oublie cette idée.

par Idaho » 08 juin 2007, 14:01

Ton aide est la bienvenue :)

Par contre je dois d'abord finir un projet en cours (cf signature) donc je ne m'y mettrai sérieusement que dans une ou deux semaines je pense.

par Sékiltoyai » 08 juin 2007, 12:57

C'est vrai qu'il y a toujours le risque d'oublier quelque chose. De toute façon tout autoriser par défaut et bloquer certaines choses, ça n'a jamais été une méthode fiable... Donc je vais plutôt m'orienter vers la création d'un petit interpréteur, avec une syntaxe identique à celle de PHP.
C'est la meilleure solution.
D'ailleurs, étant moi même intéressé par un interpréteur de code, je te propose mon aide.

par Idaho » 08 juin 2007, 10:13

En ce qui concerne runkit, je n'ai malheureusement pas la possibilité d'installer des extensions :(

C'est vrai qu'il y a toujours le risque d'oublier quelque chose. De toute façon tout autoriser par défaut et bloquer certaines choses, ça n'a jamais été une méthode fiable... Donc je vais plutôt m'orienter vers la création d'un petit interpréteur, avec une syntaxe identique à celle de PHP.

Voila, merci :)

par Sékiltoyai » 08 juin 2007, 02:48

Idaho, tu comptes toujours faire exécuter le code par PHP ?
Tu ne trouves pas que serait mieux de l'exécuter toi même, c'est à dire implémenter un petit langage tout con proche de php ?

par Hubert Roksor » 08 juin 2007, 02:36

je n'y avai pas pensé.
On ne peut pas penser à tout, tu vas invariablement oublier des trucs et quelques qui a du temps devant lui pourra les exploiter, c'est pour ça que je disais que ce genre de page est voué à l'échec. À la rigueur, regarde du côté de "runkit", il était possible de créer des "sandbox" et désactiver des fonctions à l'interieur de ces sandboxes, ce serait plus fiable qu'un validateur, mais je ne suis pas sûr que runkit soit maintenu à jour.
Au passage je n'ai pas bien compris celui-ci, à aucun moment il n'est executé..
Il doit falloir remplacer \\1 par \\0, ce n'est qu'un exemple approximatif, pour te donner une idée du principe (modifieur "e" de preg_replace()).

Enfin, bonne chance quand même.

par Idaho » 08 juin 2007, 02:14

Oui certaines fonctions inoffensives (enfin je crois) seront accessibles (sur les chaines de caractères et mathématiques), rien d'autre.
Donc pour les fonctions appelées explicitement, pas de souci.

* Ensuite pour les fonctions appelées de manière fourbe :
$x = 'eval';
$x($evilcode);
Il suffit de vérifier qu'un nom de variable ne précède pas le symbole '('.

* Enfin pour les variables variables, du genre :
${'secr'.$i}
Il faut simplement s'assurer que le token '$' n'est pas présent (correspondant au $ du début, ${...) dans le code. En effet pour les 'vraies' variables ('$' inclus) le token T_VARIABLE est utilisé.


Il me semble que ça résout les problèmes cités précédemment. Enfin si je n'ai rien oublié...

par Sékiltoyai » 08 juin 2007, 01:19

Il faudrait que tu fasses une liste des fonctions autorisées, si tu autorises l'utilisation de certaines fonctions non critiques (is_int ou abs...).

par Idaho » 08 juin 2007, 01:17

Il pourrait essayer mais ça ne marcherai pas :p
Les fonctions peuvent etre toutes vérifiées, leur nom figure dans T_STRING, il suffit de le comparer à une liste de fonctions autorisées. Par contre il faut effectivement penser à interdire aussi create_function (et juste garder le mot function), je n'y avai pas pensé. Enfin cela rend ces trois là inutilisables :
call_user_func(create_function('', 'eval(\'exec("rm -rf /tout/ton/disque")\')'));
ob_start('eval');echo "exec('rm -rf /oh/no');";
Au passage je n'ai pas bien compris celui-ci, à aucun moment il n'est executé.. :
preg_replace('#.*#e', "eval('\\1');", "exec('rm -rf /oh/no');");


Par contre pour le dernier je m'avoue vaincu pour le moment :
$x = 'eval';
$x($code_malveillant);

Je devrait peut être faire l'inverse, et vérifier que les lignes correspondent à des masques, en imposant une action par ligne... mais c'est moins drôle.

par Sékiltoyai » 08 juin 2007, 01:14

Oui, mais à ce moment là ce sera à lui de ne laisser que les syntaxes de base. De toute facon, si Idaho doit recoder entièrement l'interpréteur PHP, il va en avoir pour longtemps...

par Hubert Roksor » 08 juin 2007, 00:55

Quand Sékiltoyai parle d'analyseur, c'est pas un truc incorporé à PHP que tu aurais raté en feuilletant le manuel, désolé :lol:

En fait ça correspond à ce dont tu parles, une routine "maison" qui efface tout ce qui parait suspect. L'embêtant c'est qu'il y a toujours un moyen de contourner ce genre de protections donc si quelqu'un veut nuire au site et est prêt à y passer un petit peu de temps, il y parviendra.

Quelques exemples de trucs qu'un utilisateur malveillant pourrait essayer sur ton système
$x = 'eval';
$x($code_malveillant);
call_user_func(create_function('', 'eval(\'exec("rm -rf /tout/ton/disque")\')'));
ob_start('eval');echo "exec('rm -rf /oh/no');";
preg_replace('#.*#e', "eval('\\1');", "exec('rm -rf /oh/no');");
Je n'en ai testé aucun, mais ça te donne une idée du genre de trucs tordus qu'on peut essayer pour passer outre toutes sortes de protections.

par Idaho » 08 juin 2007, 00:44

Merci pour votre aide :merci:
Il faudrait limite un analyseur derrière pour détecter les actes de malveillance ou de maladresse (le while(1) est un bon exemple) avant d'exécuter le code...
Tu pourrai préciser un peu ? :)


Sinon pour le reste:
A priori il est possible de détecter facilement tous les éléments dangereux (includes, fonctions, classes, etc) avec le découpage en tokkens de l'analyseur, ou au contraire de faire une liste avec les éléments autorisés.

Par contre il reste un problème au niveau des variables.
- Tout d'abord, il est possible d'accéder aux variables de la page. Je ne peux pas me contenter d'analyser le contenu des T_VARIABLE (c'est à dire le nom des variables) à cause des variables variables.
- Du coup, il est possible que le code se réécrive sur lui-même. Du genre ... $this->code = "readfile('config.php'); ... " au milieu du code. Surtout que dans mon cas le code doit être executé plusieurs fois, donc dès la seconde fois le nouveau code sera exécuté.


Voila... si vous avez une idée pour remédier à ce problème, elle est la bienvenue :) Peut-etre qu'empecher les variables variables résoudrait le problème ?

par Sékiltoyai » 07 juin 2007, 22:09

Ouaip, c'est ce que j'allais proposer. Tu peux essayer une solution basée sur le tokenizer, mais il va te falloir gérer quelles fonctions tu veux autoriser et quelles fonctions tu veux interdire donc c'est pas gagné. Sans oublier la possibilité de ralentir ton serveur avec une boucle infinie comme
while(1){md5(time());}
Sans oublier tous les fopen(), etc... qui pourraient avoir de grosses conséquences.
Il faudrait limite un analyseur derrière pour détecter les actes de malveillance ou de maladresse (le while(1) est un bon exemple) avant d'exécuter le code...

par Hubert Roksor » 07 juin 2007, 19:43

Ouaip, c'est ce que j'allais proposer. Tu peux essayer une solution basée sur le tokenizer, mais il va te falloir gérer quelles fonctions tu veux autoriser et quelles fonctions tu veux interdire donc c'est pas gagné. Sans oublier la possibilité de ralentir ton serveur avec une boucle infinie comme
while(1){md5(time());}
Sans oublier tous les fopen(), etc... qui pourraient avoir de grosses conséquences.

par Idaho » 07 juin 2007, 19:12

Oui c'est sur qu'il faut être très prudent. C'est aussi un peu pour ça que je demande votre avis ^^

Je viens de découvrir la fonction token_get_all, je vais regarder un peu et je vous dirai quoi :)