J'aime écrire un système de modèle en Python, qui permet d'inclure des fichiers.
par exemple.
C'est un modèle
Vous pouvez inclure des fichiers en toute sécurité avec safe\_include\`othertemplate.rst\`
Comme vous le savez, l'inclusion de fichiers peut être dangereuse. Par exemple, si j'utilise le système de modèle dans une application web qui permet aux utilisateurs de créer leurs propres modèles, ils pourraient faire quelque chose comme
Je veux vos mots de passe: safe\_include\`/etc/password\`
Par conséquent, je dois limiter l'inclusion de fichiers aux fichiers qui se trouvent par exemple dans un certain sous-répertoire (par exemple /home/user/templates
)
La question est maintenant : Comment puis-je vérifier si /home/user/templates/includes/inc1.rst
se trouve dans un sous-répertoire de /home/user/templates
?
Le code suivant fonctionnerait-il et serait-il sécurisé?
import os.path
def in_directory(file, directory, allow_symlink = False):
#rendre tout deux en absolu
directory = os.path.abspath(directory)
file = os.path.abspath(file)
#vérifier si le fichier est un lien symbolique, et dans ce cas, retourner faux s'ils ne sont pas autorisés
if not allow_symlink and os.path.islink(file):
return False
#retourner vrai, si le préfixe commun des deux est égal au répertoire
#par exemple, /a/b/c/d.rst et le répertoire est /a/b, le préfixe commun est /a/b
return os.path.commonprefix([file, directory]) == directory
Tant que allow_symlink
est False, cela devrait être sécurisé, je pense. Autoriser les liens symboliques bien sûr le rendrait insecure si l'utilisateur peut créer de tels liens.
MISE À JOUR - Solution Le code ci-dessus ne fonctionne pas si des répertoires intermédiaires sont des liens symboliques. Pour prévenir cela, vous devez utiliser realpath
au lieu de abspath
.
MISE À JOUR: ajouter un / final au répertoire pour résoudre le problème avec commonprefix() souligné par Reorx.
Cela rend également allow_symlink
inutile car les liens symboliques sont étendus vers leur destination réelle
import os.path
def in_directory(file, directory):
#rendre tout deux en absolu
directory = os.path.join(os.path.realpath(directory), '')
file = os.path.realpath(file)
#retourner vrai, si le préfixe commun des deux est égal au répertoire
#par exemple, /a/b/c/d.rst et le répertoire est /a/b, le préfixe commun est /a/b
return os.path.commonprefix([file, directory]) == directory