realpath secure ?

date
15 / 3 / 2010
date
C
comments
3

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 post

IPV6 step one two

Next post

blog.philpep.org rune pblog2

Comments: 3

MAIDEN 15 / 3 / 2010 at 3:2

"Sans me venter j'ai souvent des idées géniales en informatique" Mais pas en orthographe ^^ ==> vanter

philpep 15 / 3 / 2010 at 15:13

Corrigé, merci :)

kAworu 21 / 3 / 2010 at 14:17

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);
}

Add a comment

captcha



Comments are formatted using markdown syntax.