realpath secure ?
Dans le cadre d'une application serveur (type transfert de fichier : http, ftp, ...), pour contrôler l'accès aux fichiers j'utilise realpath(3). Cette fonction permet d'avoir le path (chemin) réel d'un fichier, sans lien relatif dans un des dossiers. Ainsi on a juste à faire un strncmp(3) pour le comparer à la racine de l'application.
Par exemple une partie du code du serveur HTTP que je suis en train de coder (uri est quelque chose de la forme /../foo/bar/../machin.html et conf_root la racine du style /usr/local/www/
char path[PATH_MAX]; char root[PATH_MAX]; if (!realpath(uri+1, path) || !realpath(conf_root, root) || strncmp(path, root, strlen(root)) != 0) return send_error(404);
Prenez ce post pour une question, à part le chroot(2) et realpath, comment bien contrôler l'accès aux fichiers ?
J'y connais rien en filesystems, mais si on pouvait avoir un moyen rapide de savoir si un fichier est dans tel ou tel fichier ce serait grandement pratique. Sans me vanter j'ai souvent des idées géniales en informatique, mais bien souvent ça a été pensé et implémenté depuis plus de 10 ans ! Du coup si vous avez plus d'information, je suis prêt à converser sur ce sujet avec vous...
Previous postIPV6 step one two |
Next postblog.philpep.org rune pblog2 |
Comments: 3
"Sans me venter j'ai souvent des idées géniales en informatique" Mais pas en orthographe ^^ ==> vanter
Corrigé, merci :)
Salut! Voilà un petit bout de code qui permet de check un path à partir d'un workdir précis, car si tu call realpath(3) directement c'est interprété à partir du CWD ou t'as lancé le processus du serveur web, et ça te permet pas de gérer plusieurs hosts.
Warning: codé avec les pieds du dimanche (et la gueule de bois qui accompagne un lendemain de samedi soir arosé) en deux minutes un sandwich à la main avec aucun check pour que ce soit plus clair (comme ça, vous êtes prévenus hein).
/* * path.c * */ #include <sys/param.h> #include <string.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { const char *workdir = "/usr/local/"; char resolved_path[PATH_MAX]; char *requested; char *pathname; size_t pathnamelen; requested = argv[1]; if (strcmp(requested, ".") == 0 || strcmp(requested, "/") == 0) requested = "/index.html"; pathnamelen = strlen(workdir) + strlen(requested); pathname = calloc(pathnamelen + 1, sizeof(char)); strcpy(pathname, workdir); strcat(pathname, requested); (void)printf(" path: %s\n", pathname); realpath(pathname, resolved_path); (void)printf("resolved: %s\n", resolved_path); (void)printf(" verdict: "); if (strncmp(workdir, resolved_path, strlen(workdir)) == 0) (void)printf("OK\n"); else (void)printf("Oups!\n"); return (0); }


3