Articles
Hier soir, j’ai eu le plaisir de partager une session de recherche avec Philippe Gamache. Nous avions besoin de données exhaustives sur PHP, et cela nous a donné l’occasion d’étudier la distribution source de ce dernier. Ce n’est pas tous les jours que l’on en apprend autant sur la plate-forme alors voici un pot-pourri de quelques trouvailles réalisées.
- La vraie connexion à MySQL avec MySQLI
- Les classes prédéfinies de PHP
- PECL pour Windows
- Milter, continuity et les SAPI
- Sécuriser la fonction mail()
La vraie connexion à MySQL : Mysqli_real_connect
Il y a une fonction mysqli_real_connect(), comme il existe une fonction myslq_real_escape_string() depuis longtemps. Il semble que MySQL aime bien faire des fonctions vraies et authentiques, en plus de fonctions… standard, pour ne pas dire fausses ou hypocrites ?
Mysqli_real_connect() est simplement une version plus complète et plus compliquée que mysqli_connect(). Son utilisation ressemble à ceci (merci à la documentation pour le code) :
<?php var_dump(mysqli_connect('localhost','user','password','base')); /* Creation d'un objet de connexion, sans être connecte */ $link = mysqli_init(); /* Definition des quelques options de connexion */ mysqli_options($link, MYSQLI_INIT_COMMAND, "SET AUTOCOMMIT=0"); mysqli_options($link, MYSQLI_OPT_CONNECT_TIMEOUT, 5); /* Connexion au serveur */ mysqli_real_connect($link, 'localhost', 'user', 'password', 'base'); /* Vérification de la connexion */ if (mysqli_connect_errno()) { printf("Echec de la connexion : %s\n", mysqli_connect_error()); exit(); } var_dump($link); ?>
En fin de compte, ces deux scripts produisent la même chose : un objet de connexion MySQLi, prêt à exécuter des requêtes.
object(mysqli)#1 (0) { } object(mysqli)#1 (0) { }
L’intérêt ici est de pouvoir effectuer des configurations du client MySQL avant la connexion, ce qui n’est pas possible à faire avec mysqli_connect (22 visites). Par exemple, activer le chiffrement et la compression de la connexion, ignorer les espaces après les noms de fonctions MySQL, ou encore retourner le nombre de lignes sélectionnées au lieu du nombre de lignes affectées.
Une fois la connexion établie, l’utilisation des ressources est identique à celle faite avec mysqli_connect (22 visites).
Au final, cet attribut ‘real’ est assez folklorique. Peut être un jour aura-t-on d’autres vrais attributs, encore plus éloquents : mysqli_real_real_real_connect(), mysqli_really_true_connect(), mysqli_yet_another_authentic_connect()… (PS : Georg, I’m just kidding !).
Les classes prédéfinies de PHP 5
En cherchant à établir une liste raisonnable de fonctions pour la directive disable_functions de php.ini, nous avons du exécuter la même recherche pour disable_classes. N’oublions pas qu’en PHP 5, de nombreuses extensions ont un double visage : procédural et orienté objet. Il ne sert à rien de désactiver mysqli_connect (22 visites) si la classe mysqli n’est pas aussi désactivée : à moins bien sûr que vous ne souhaitiez faire une chasse aux sorcières contre le procédural.
La liste des classes compilées dans PHP est obtenue avec le script ci-dessous, pourvu que vous ayez une version assez récente pour supporter get_declared_classes (11 visites)()) :
<?php print_r(get_declared_classes());?>
PHP 4.4.4, avec 18 modules compilés, donne 3 classes :
Array ( [0] => stdClass [1] => __PHP_Incomplete_Class [2] => Directory )PHP 5.2.1RC2, avec 43 modules, donne 129 classes :
Array ( [0] => stdClass [1] => Exception [2] => ErrorException [3] => ZipArchive [4] => LibXMLError [5] => XSLTProcessor [6] => XMLWriter [7] => DOMException [8] => DOMStringList [9] => DOMNameList [10] => DOMImplementationList [11] => DOMImplementationSource [12] => DOMImplementation [13] => DOMNode [14] => DOMNameSpaceNode [15] => DOMDocumentFragment [16] => DOMDocument [17] => DOMNodeList [18] => DOMNamedNodeMap [19] => DOMCharacterData [20] => DOMAttr [21] => DOMElement [22] => DOMText [23] => DOMComment [24] => DOMTypeinfo [25] => DOMUserDataHandler [26] => DOMDomError [27] => DOMErrorHandler [28] => DOMLocator [29] => DOMConfiguration [30] => DOMCdataSection [31] => DOMDocumentType [32] => DOMNotation [33] => DOMEntity [34] => DOMEntityReference [35] => DOMProcessingInstruction [36] => DOMStringExtend [37] => DOMXPath [38] => XMLReader [39] => SimpleXMLElement [40] => RecursiveIteratorIterator [41] => IteratorIterator [42] => FilterIterator [43] => RecursiveFilterIterator [44] => ParentIterator [45] => LimitIterator [46] => CachingIterator [47] => RecursiveCachingIterator [48] => NoRewindIterator [49] => AppendIterator [50] => InfiniteIterator [51] => RegexIterator [52] => RecursiveRegexIterator [53] => EmptyIterator [54] => ArrayObject [55] => ArrayIterator [56] => RecursiveArrayIterator [57] => SplFileInfo [58] => DirectoryIterator [59] => RecursiveDirectoryIterator [60] => SplFileObject [61] => SplTempFileObject [62] => SimpleXMLIterator [63] => LogicException [64] => BadFunctionCallException [65] => BadMethodCallException [66] => DomainException [67] => InvalidArgumentException [68] => LengthException [69] => OutOfRangeException [70] => RuntimeException [71] => OutOfBoundsException [72] => OverflowException [73] => RangeException [74] => UnderflowException [75] => UnexpectedValueException [76] => SplObjectStorage [77] => PDOException [78] => PDO [79] => PDOStatement [80] => PDORow [81] => SoapClient [82] => SoapVar [83] => SoapServer [84] => SoapFault [85] => SoapParam [86] => SoapHeader [87] => SQLiteDatabase [88] => SQLiteResult [89] => SQLiteUnbuffered [90] => SQLiteException [91] => __PHP_Incomplete_Class [92] => php_user_filter [93] => Directory [94] => ReflectionException [95] => Reflection [96] => ReflectionFunctionAbstract [97] => ReflectionFunction [98] => ReflectionParameter [99] => ReflectionMethod [100] => ReflectionClass [101] => ReflectionObject [102] => ReflectionProperty [103] => ReflectionExtension [104] => mysqli_sql_exception [105] => mysqli_driver [106] => mysqli [107] => mysqli_warning [108] => mysqli_result [109] => mysqli_stmt [110] => SWFShape [111] => SWFFill [112] => SWFGradient [113] => SWFBitmap [114] => SWFText [115] => SWFTextField [116] => SWFFont [117] => SWFDisplayItem [118] => SWFMovie [119] => SWFButton [120] => SWFAction [121] => SWFMorph [122] => SWFSprite [123] => SWFSound [124] => SWFFontChar [125] => SWFSoundInstance [126] => SWFVideoStream [127] => DateTime [128] => DateTimeZone )
Oui, pas moins de 129 classes prédéfinies en PHP. Je peux vous garantir qu’elles ne me servent pas toutes… Probablement deux ou trois d’entre elles, et indirectement une douzaine.
En lisant les noms, on identifie vite les extensions qui les propose : zip, date, ming (swf), dom, xml, spl, etc.
PECL pour Windows : PECL4win
J’avoue, je n’utilise pas Microsoft Windows. Ce qui fait que je n’ai jamais eu à utiliser le site de PECL4Win (26 visites). Ce site est en fait l’alter ego de PECL (20 visites), la bibliothèque d’extensions PHP. Cette bibliothèque est une merveille : vous y trouverez des extensions dont vous n’avez jamais osé révé : manipulations de vidéo, production de sons, des bases de données inconnues, des réseaux neuronaux, des accélérateurs, de vieilles extensions obsolètes ainsi que les étoiles de demain.
D’ailleurs, j’attend avec impatience la session de John Coggeshall (12 visites) à la John's Top PECL Picks (5 visites) : Back to VC6 for PHP Windows build (12 visites). (Prononcez-le à l’anglaise et à haute voix… juste pour voir)
Mais PECL contient des sources, et si c’est bien pour une distribution linux, c’est inutilisable pour un utilisateur Windows, qui a besoin de versions compilées (à moins d’être comme Edin Kadribašić (Snaps PHP 6 (8 visites)) et aimer souffrir.
Heureusement, il y a pecl4win.php.net, qui recense un maximum de fichiers DLL, destinés à ajouter encore des masses de fonctionnalités à PHP. Il y a là des versions pour PHP 4.3 à 6.0.
Oui, il y a des versions de DLL destinées à PHP 6.0. Vous n’avez pas encore PHP 6 ? Pourtant, PHP 6.0 disponible, sur le site de Snaps : Wamp server (8 visites), sous forme de version de développement.
Je n’ai pas visité le site plus en détails, mais je suis certain qu’il va servir à beaucoup de monde. Peut être verra t on un paquet ‘maximum’ apparaître chez Milter (14 visites), avec une maximum d’extensions PHP ?
milter et continuity ?
En cherchant l’extension iisfunc de PHP, nous avons étudié le contenu du dossier ‘sapi’ de la distribution source de PHP. C’est là que nous pouvions trouver les interfaces avec les serveurs Web. On y trouve par exemple les interfaces fastcgi, nsapi ou toutes les variations d’apache. Evidemment, pas de iisfunc, puisque cette interface est spécifique Windows, donc disponible dans pecl4win et inutile dans la distribution source.
Mais en étudiant la liste, nous avons trouvé au moins deux autres interfaces étranges, donc nous n’avions jamais entendu parlé. Milter et continuity. Diable, qu’est-ce donc ?
Milter (ashpool (17 visites)) est une interface pour sendmail : Sendmail's Content Management API. Elle permet de traiter les messages qui transitent par le serveur de mail, de les transformer ou de les détruire sur le serveur. PHP dispose d’une interface particulière pour ce serveur : cela permet d’écrire des scripts PHP pour analyser le contenu des mails, et de développer son propre filtre bayesien ou de tester une nouvelle technique.
Ici, sendmail prend la place d’Apache : c’est le serveur qui sert de cadre pour l’exécution de PHP, et l’appelle quand c’est nécessaire. Cette interface est la réplique de celle qui est faite avec Apache. Avec Apache, PHP transforme une URL en une page Web (ou un contenu multimédia). Ici, PHP transforme un message mail en un autre message mail (ou son absence).
Je ne connais personne qui utilise cette interface. Elle date de 2003.
Continuity s’avère que c’est un CMS écrit en C. Continuity CMS (13 visites) et PHP.pm (6 visites). Il a été difficile de comprendre ce que cela fait, ou si c’est encore un produit vivant : le site est très institutionnel, et porte encore le copyright 2006. Tout ça semble bien mort…
L’utilisation de PHP dans un CMS écrit en C peut sembler paradoxal. Mais après avoir compris le fonctionnement de milter, cela devient évident. Selon toutes vraisemblances, Continuity propose une application de gestion de contenus. Elle se charge de différents points, comme la publication du contenu, l’interface, le stockage, les statistiques et le suivi client... Or, tout le monde le sait, un CMS a besoin de personnalisation, et ce n’est pas toujours évident à faire en langage C. Pour éviter de redévelopper tout un langage de personnalisation, continuity a décidé d’utiliser PHP. Des scripts faciles à faire, qui se greffent là où le CMS autorise les personnalistion. Ainsi, le CMS fournit un contenu à PHP, et obtient de PHP un contenu modifié en retour. Les clients peuvent prendre en main facilement leur CMS, profiter de fonctionnalités centralisées, mais personnalisées sans avoir à apprendre toute une nouvelle plate-forme.
C’est l’utilisation classique de PHP sous forme intégrée (dite aussi embedded). En général on voit cette utilisation apparaître dans deux cas : soit les besoins de configuration se développent très vite, au point qu’il faut un outil pour la maîtriser. Par exemple, le fichier de configuration était un fichier INI, mais il devient trop compliqué. On branche alors PHP, qui sait prendre un fichier XML ou une base SQLite et la transformer au format maison. L’autre cas, c’est quand il faut fournir des informations au système en provenance de sources très variées. PHP est le candidat idéal pour servir de transformateur (de glue, en anglais, ou mortier). Le système fournit à PHP l’identification des ressources à interroger, et ce dernier se charge d’y lire les informations et de les préparer pour nourrir le système. Le tout, sous forme de script simples.
Dernière remarque sur cette visite éclair des API : on parle généralement d’extensions pour PHP, quand c’est PHP qui charge une bibliothèque externe pour l’utiliser : par exemple, PHP et l’extension mcrypt, ou l’extension mysqli. Mais lorsque c’est une bibliothèque externe ou un démon qui charge PHP, on parle d’interface serveur, soit Server API, ou encore sapi. Par exemple, PHP existe sous forme intégré à Perl :
php-mail-header (22 visites). Je ne sais pas si on parle de Perl API ou de PAPI.…
mail_extra_headers
Enfin, certaines choses sont tellement habituelles qu’on finit par croire qu’elles sont normales. C’est le cas de cette directive, que je retrouve régulièrement sur les solutions d’hébergement de Nexen services.
Tiré d’un patch de choon (dotdeb (12 visites)), et adapté par Guillaume Plessis (Ilia Alshanetsky (17 visites)) pour la plate-forme d’hébergement (mail logging for PHP (23 visites)), ce petit patch ajoute simplement un entête supplémentaire aux mails qui sortent du serveur. Par exemple :
X-PHP-Script: www.example.com/~user/testapp/send-mail.php for 10.0.0.1
Il y a ainsi l’URL utilisée et l’adresse IP de l’émetteur qui partent avec chaque utilisation de la fonction mail() de PHP. Si un spammeur a repéré un script de mail mal protégé, on va trouver immédiatement le script fautif, et le signaler au client. On peut aussi trouver l’IP de l’émetteur, et le bloquer sur le serveur ou le signaler à des systèmes de listing.
Pour maîtriser efficacement l’utilisation de la fonction mail, il y a aussi le patch d’PHPportail (31 visites): .
Au lieu de marquer les scripts, les envois sont notés dans un fichier de log. Il suffit alors d’analyser le fichier pour identifier les scripts qui sont mal utilisés ou les IP qui abusent d’un script. L’avantage de cette technique est que l’on peut anticiper les problèmes directement depuis le serveur. Par contre, le patch de choon donne à une victime de spam des outils pour remonter des informations utiles à l’adminstration du site.
Enfin, il y a aussi la directive mail.force_extra_parameters : elle remplace le 5eme argument de la fonction mail() par une série d’arguments imposés par l’administrateur. Cela évite les injections de mails via le 5eme argument de mail() (mais pas les injections qui passent par les autres arguments). Cette directive est intégrée en PHP, dans la distribution standard.
Voilà. Si vous avez lu jusqu’ici, j’espère que vous en aurez aussi appris, tout comme nous.
Crédit
Cette session de trouvaille a été menée avec Philippe Gamache, responsable de . Nous travaillons ensemble sur un livre consacré à la sécurité : on vous en reparlera bientôt.
| < Précédent | Suivant > |
|---|
Commentaires
Vous pouvez ajouter votre commentaire! |
Vous devez vous connecter pour commenter


