Les attaques par canonicalisation (2/2)
Par amethyste le Oct 24, 2004 | Dans focus | Réagir »
Le blog précédent avait pour objet de poser le problème et se terminait par une question:
Existe t'il des algorithmes capables de dire si deux chemins pointent sur la même ressource?
L'équipe de développement de la BCL dispose de son propre blog. Et il y a quelques jours Brian Grunkemeyer a justement abordé cette question.
Disons le tout de suite, Brian est très pessimiste avec des arguments de poids.
Tout d'abord, quand bien même on se lancerait dans l'aventure, le coût d'une telle opération est élevé et les performances de l'application ne peuvent que s'en ressentir.
Il est clair que si l'on peut obtenir le nom canonique d'un fichier, le problème est résolu. La seule manière fiable d'obtenir cette information (en tout cas sous Windows) est de l'ouvrir afin d'en obtenir un handle. Cette opération est évidemment très coûteuse surtout si le fichier se trouve sur un autre serveur et pose différents problèmes pratiques. En particulier elle suppose que la ressource existe et est accessible (droits, serveur disponible...).
Dans mon précédent blog j'ai proposé plusieurs alternatives qui ont pour particularité d'être spécifiques à une classe de problème. Peut t'on prendre de la hauteur avec des méthodes plus globales?
Une approche possible est celle du compromis acceptable. En langage gourou on appelle cela les chemins normalisés.
On ne cherche pas absolument à canonaliser le chemin, mais à faire au mieux. En gros on résout les alias les plus évidents.
.NET propose la méthode Path.GetFullPath() pour normaliser un chemin d'accès.
Par exemple, c:\..\toto.txt est résolu en c:\toto.txt, ce qui explique la note de mon blog.
C'est en particulier ainsi que fonctionne FileIOPermission.
Disons le tout de suite la normalisation est un problème plus ardu qu'il n'y parait. Brian pointe au moins 3 difficultés que nous allons analyser:
- Les permissions d'accès à un fichier sont accordées sur la base du nom et du répertoire. Par conséquent les alias (les pseudos si vous voulez) ne sont pas couverts.
- au delà du problème des alias, chaque système d'exploitation dispose de ses règles de nommage.
- Basiquement on fait une comparaison de chaînes. Cette opération est en réalité plus subtile qu'il n'y paraît.
Le premier point est complexe en raison du nombre de possibilités.
Sous Windows cela peut aller du simple lecteur virtuel ajouté avec la commande DOS subst ou les reparse point de NTFS.
Mais le chemin peut très bien pointer vers d'autres OS comme UNIX/LINUX avec ses points de montage ou ses liens symboliques.
Les règles de nommage sont un deuxième écueil. Par exemple FAT et NTFS sont insensibles à la casse. Ce n'est pas le cas d'UNIX par contre.
Certains caractères ont un sens spécial comme le point en préfix sous UNIX. Certains OS acceptent des nom du style c:\..\toto.txt d'autres non. L'imagination est sans limite en la matière.
La comparaison des chaîne est également une source de surprises en tout genre.
Pour NTFS un nom de fichier est donné sous la forme d'une chaîne Unicode et presque tous les caractères sont autorisés. De plus NTFS considère TOTO et toto comme identiques. Pour savoir que ces deux chaînes sont identiques bien qu'écrites avec des caractères unicodes différents, la CLI dispose d'une table de correspondance entre les formes majuscules et minuscules.
Puisque la CLI est indépendante de l'OS où on l'a implémenté, elle fournit sa propre table et n'utilise pas celle proposée par Windows par exemple. Par conséquent rien ne garantit que ces tables soient identiques et potentiellement deux fichiers peuvent être différents pour l'OS, mais apparaître comme identique pour .NET!
On peut trouver cela curieux puisque en fait cette table est fournie par la norme Unicode elle-même.
La raison est que le cycle de vie de la norme n'est pas le même que celui des systèmes d'exploitation. A tout moment des caractères nouveaux peuvent apparaître, mais également des erreurs être corrigées.
Comme on le voit, la comparaison de chaînes de caractères n'est pas une opération aussi simple que l'on pourrait penser et pose en soi des problèmes de sécurité.
En pratique le problème est très limité. Les erreurs et les ajouts sont rares et concernent surtout des caractères obscurs peu utilisés, en tout cas pour nommer un fichier. Mais si vous vous intéressez aux problèmes de sécurité il est important d'en être avertit.
Que pouvons nous conclure?
Dans tous les cas on compare des noms de fichiers.
Comparer des noms canoniques est très fiable, mais c'est une information coûteuse à obtenir et parfois même inaccessible.
Comparer des noms normalisés est plus efficace, mais signifie une prise de risque et un taux d'échec plus fort. Par contre il est toujours possible de normaliser.
En ce qui concerne .NET, Microsoft a choisi la deuxième solution.
Evidemment j'entends déjà les gourous en "Microsoft bashing" hurler.
D'abord aucune méthode n'est pas fiable à 100% ne serait-ce qu'en raison des problèmes de comparaison de chaînes unicodes. Ensuite comment s'en sortir si la ressource n'est pas accessible?
De toute façon une bonne approche de la sécurité commence d'abord par évaluer objectivement la menace.
Vous devrez alors prendre des décisions en fonction du contexte. Cela suppose de savoir évaluer votre surface d'attaque et donc de connaître les faiblesses de chaque maillon de votre chaîne de sécurité de façon à les utiliser à bon escient. C'est en fonction de cette analyse que vous déciderez s'il est utile ou non d'implémenter des algorithmes plus forts.
C'est toute la différence entre une dispute de bac à sable et une approche professionnelle.
Pour en savoir plus allez sur le site de l'UNICODE: http://www.unicode.org.
Il y a pas mal d'informations liées aux problème de canonicalisation et de normalisation. Par contre c'est en anglais.
5:24/10/2004
Améthyste
Aucun commentaire pour le moment
Laisser un commentaire
| « Pas de géopolitique ici! | Les attaques par canonicalisation (1/2) » |