DokuWiki

It's better when it's simple

Outils pour utilisateurs

Outils du site


fr:devel:security

Guide de sécurité à destination des auteurs d'extensions

Créer une extension pour DokuWiki est très simple pour les programmeurs novices en PHP. Cependant et pour ne pas compromettre la sécurité de l'ensemble du wiki et du système sur lequel il est installé, vous devriez suivre ce guide minimal indiqué sur cette page.

:!: Ceux qui souhaitent aider à la construction de cette page sont les bienvenus. Celle-ci reste peu complète (au sens d'accessible) et nécessite davantage d'informations, de liens ou d'exemples

Sommaire

Voici quelques exemples d'une liste bien plus longue de failles communes de sécurité, que vous pouvez trouver sur cette page :

  • Cross Site Scripting (XSS) – insertion de codes « malicieux » par le biais de la page pour corrompre la page affichée sur le navigateur de l'utilisateur.
  • Cross Site Request Forgery (CSRF) – des astuces pour vous permettre de faire vous-même, sans le savoir, des actions nuisibles sur votre site
  • Remote Code Inclusion –- comprend un code sur le serveur qui y est exécuté
  • Information leaks – diffusion d'informations non autorisé à l'origine par l'administrateur
  • SQL injection – on peut faire des demandes non souhaitées sur vos données

Vous trouvez sur Signaler des problèmes de sécurité quelques informations supplémentaires sur ces points.

Cross Site Scripting (XSS)

C'est probablement la vulnérabilité la plus courante que l'on trouve dans les extensions DokuWiki.

Le Cross Site Scripting désigne une attaque par laquelle un code JavaScript malveillant est introduit dans un site web. Il peut être utilisé pour rediriger des utilisateurs innocents vers des sites web malveillants ou pour voler des cookies d'authentification.

Le mécanisme de gestion des extensions de DokuWiki permet aux développeurs de greffon un compromis intéressant de flexibilité. Dans le cas des greffons de syntaxe en particulier, le cadre donne aux extensions la possibilité de travailler avec des sorties brutes non traitées. Cela signifie que les données de la page wiki qui atteignent votre greffon n'ont pas été traitées du tout. Et il n'y aura pas de traitement supplémentaire sur la sortie après qu'elle ait quitté votre greffon.

« Échapper » le contenu

La base minimale de sécurité de votre greffon devrait être de s'assurer que toute sortie de données brutes soit convertie en entités HTML par la fonction PHP htmlspecialchars. DokuWiki fournit pour cela un raccourci pratique appelé hsc () pour la fonction. Les valeurs URL doivent être échappés en utilisant rawurlencode.

En outre toutes les données wiki extraites et utilisées en interne (par exemple les noms d'utilisateur), doivent être traitées avec méfiance.

Vérifier les données entrantes

Vérifier toujours toutes les données entrantes. Pour cela utiliser les filtres, listes blanches ou la conversions exactes vers le type de données de la variable. Par exemple : préférer un variable de type entier à une variable de type texte qui contient les caractères d'un type entier (plutôt 42 que '42'). Assurez-vous que vous avez seulement les données que vous autorisez.

Voir également

Exemples typiques de vulnérabilités

Vous trouverez ci-dessous quelques problèmes très courants. Les exemples sont très simples pour rendre le problème général clair. Votre greffon est probablement plus compliqué, mais vous devez garder en mémoire la logique de ces types de vulnérabilités.

Corps syntaxiques

De nombreux greffons syntaxiques simples prennent en charge les entrées de l'utilisateur et les formatent en HTML personnalisé.

Exemple : Voici un greffon syntaxique abrégé pour mettre en forme une entrée donnée dans une balise en gras.

class syntax_plugin_bold extends DokuWiki_Syntax_Plugin {
    // common plugin functions ommited
 
    function connectTo($mode) {
        $this->Lexer->addSpecialPattern('!!!.*?!!!',$mode,'plugin_bold');
    }
 
    function handle($match, $state, $pos, &$handler){
        return array(substring($match,3,-3));
    }
 
    function render($mode, &$R, $data) {
        if($mode != 'xhtml') return false;
        $R->doc .= '<b>'.$data[0].'</b>';  //pas d'échappement
    }
}

Comme vous pouvez le voir, les données d'entrée brutes saisies dans le modèle de lexer sont simplement transmises à la méthode de rendu, où aucun échappement n'est effectuée. Les utilisateurs malveillants peuvent introduire le code JavaScript et HTML qu'ils veulent.

La solution est simple : échapper correctement.

class syntax_plugin_bold extends DokuWiki_Syntax_Plugin {
    // common plugin functions ommited
 
    function connectTo($mode) {
        $this->Lexer->addSpecialPattern('!!!.*?!!!',$mode,'plugin_bold');
    }
 
    function handle($match, $state, $pos, &$handler){
        return array(substring($match,3,-3));
    }
 
    function render($mode, &$R, $data) {
        if($mode != 'xhtml') return false;
        $R->doc .= '<b>'.htmlspecialchars($data[0]).'</b>'; //échappement
    }
}

Formulaires

Lorsque votre greffon fournit un formulaire, il est très courant de valider la saisie et de ré-afficher le formulaire avec la saisie reçue de l'utilisateur lorsqu'une erreur de validation se produit.

Exemple : Ce qui suit montre un formulaire vulnérable à une attaque XSS parce qu'il n'échappe pas correctement l'entrée fournie par l'utilisateur :

<form action="" method="post">
    <input type="text" name="q" value="<?php echo $_REQUEST['q']?>" /> 
    <input type="submit" />                     //pas d'échappement
</form>

Fournir "><script>alert('bang')</script> comme entrée utilisateur exploiterait la vulnérabilité.

Pour corriger le formulaire, utilisez la fonction htmlspecialchars() ou le raccourci DokuWiki hsc() :

<form action="" method="post">
    <input type="text" name="q" value="<?php echo hsc($_REQUEST['q'])?>" />
    <input type="submit" />                                      //échappement
</form>

Classes et autres Attributs

Souvent, les greffons acceptent plusieurs paramètres et options qui sont utilisés pour modifier la sortie du greffon.

Imaginez un greffon acceptant l'entrée suivante pour afficher une boîte de message :

<msg warning>Do not believe anything!</msg>

Dans la méthode de rendu de cette syntaxe, il pourrait y avoir un code comme celui-ci :

$renderer->doc .= '<div class="msg_'.$class.'">'  //$class peut être n'importe quoi
                       .htmlspecialchars($message)
                 .'</div>';
 

Comme vous pouvez le constater, le message lui-même est bien échappé, mais pas la classe. Au lieu de s'échapper, il pourrait être plus judicieux d'utiliser une liste blanche de classes autorisées avec une option de repli par défaut :

$allowed = array('notice','info','warning','error');   //liste blanche
if(!in_array($class,$allowed){                         
    $class = 'notice'; //unknown input, fall back to a sane default
}
$renderer->doc .= '<div class="msg_'.$class.'">'
                       .htmlspecialchars($message)
                 .'</div>';

URLs comme données en entrée

Lorsqu'un greffon accepte des URLs en entrée, vous devez vous assurer que les utilisateurs ne peuvent pas passer le pseudo protocole javascript://.

Voici un exemple de vérification très simple pour s'assurer que seules les URL http et https sont utilisées.

// URL vide sur la non-concordance des protocoles
if(!preg_match('/^https?:\/\//i',$url)) $url = ''; 

Cross Site Request Forgery (CSRF)

Cette vulnérabilité apparaît souvent dans les greffons en raison du manque de compréhension de cette question, souvent confondue avec le XSS.

Cross Site Request Forgery est une attaque où le navigateur de la victime est piégé par un site malveillant pour demander une page sur un site vulnérable afin d'effectuer une action non désirée. L'attaque suppose que le navigateur de la victime possède les autorisations nécessaires pour modifier quelque chose sur le site vulnérable.

Ajouter un jeton de sécurité

DokuWiki offre des fonctions pour vous aider à lutter contre les attaques de la CSRF : getSecurityToken() et checkSecurityToken(). Notez que dans les dernières versions de DokuWiki, vous pouvez utiliser formSecurityToken() au lieu de getSecurityToken(). Cette dernière ne vous donnera que la valeur du jeton, mais l'autre affichera ou retournera un <div> avec une entrée cachée du nom “sectok” et donnera la valeur du jeton de sécurité.

Voir aussi

Exemple typique de vulnérabilité

Voici l'exemple le plus simple pour commencer. Vous avez peut-être un greffon plus compliqué à sécuriser, voici un exemple simple basé sur le formulaire.

Imaginez que vous vouliez savoir quelque chose qui puisse être répondu par Oui ou Non, vous auriez un formulaire de ce type :

<form action="" method="GET">
    <input type="radio" name="yn" value="Yes" />
    <input type="radio" name="yn" value="No" />
    <input type="submit" value="Answer" />
</form>

Ensuite, vous traitez ce formulaire de cette façon :

if(isset($_GET['yn'])){
    do_something_with_yn($_GET['yn']);
}

Un utilisateur est donc connecté pour répondre à cette question, mais il ne connaît pas encore la réponse. Laissons lui le temps de réfléchir et de naviguer sur le web… Maintenant, l'utilisateur visite un site web malveillant, qui sait ou non qu'il est connecté à votre DokuWiki. Dans ce site web, le développeur a inclus cette balise d'image HTML :

<img src="http://your.dokuwi.ki/formpage?yn=Yes" />

Que fera alors le navigateur de l'utilisateur ?

Le navigateur traitera cette image comme toute autre et enverra une demande à cette URL. Votre greffon verra alors que $_GET['yn'] est défini et appellera la fonction do_something_with_yn().

C'est l'un des exemples de CSRF. Maintenant, comment remédier à cette faille de sécurité ?

Prévenir CSRF

Vous vous souvenez de votre formulaire ci-dessus ? Ajoutons une entrée dans celui-ci :

<form action="" method="GET">
    <input type="hidden" name="sectok" value="<?php getSecurityToken(); ?>" />
    <input type="radio" name="yn" value="Yes" />
    <input type="radio" name="yn" value="No" />
    <input type="submit" value="Answer" />
</form>

Voyez-vous la première entrée ? Oui ? Bien. Vous devez maintenant vérifier le jeton de sécurité lorsque vous recevez le formulaire, avant de le traiter :

if(isset($_GET['yn']) && checkSecurityToken()) {
    do_something_with_yn($_GET['yn']);
}

Comme le site web malveillant ne trouvera jamais la valeur de l'entrée cachée “sectok”, votre formulaire n'est plus vulnérable à la CSRF.

Note: Si le jeton de sécurité n'est pas valide, la fonction checkSecurityToken() affiche un message qui en informe l'utilisateur.

Inclusion de codes à distance

Cette attaque permet à un attaquant d'injecter du code (PHP) dans votre application. Cela peut se produire en incluant des fichiers, ou en utilisant des fonctions d'opérations non sécurisées comme eval ou system.

Filtrez toujours toute entrée qui sera utilisée pour charger des fichiers ou qui est passée en argument à des commandes externes.

Fuites d'informations

Cette attaque peut conduire à exposer des fichiers qui devraient normalement être protégés par les ACL de DokuWiki comme elle pourrait exposer des fichiers sur le serveur (comme /etc/passwd).

Filtrez toujours toute entrée qui sera utilisée pour charger des fichiers ou qui est passée en argument à des commandes externes.

Utilisez toujours les fonctions de vérification des ACL de DokuWiki lorsque vous accédez aux données de la page.

Injection SQL

Cette attaque est rarement pertinente dans DokuWiki car aucune base de données n'est utilisée. Cependant, si votre extension accède à une base de données, il échappe toujours à toutes les valeurs avant de les utiliser dans les instructions SQL.

Plus d'infos :

Signaler des problèmes de sécurité

Si vous rencontrez un problème avec un greffon, veuillez en informer l'auteur par courrier électronique, en mettant éventuellement Andi ou la liste de diffusion en CC.

En outre, un champ “securityissue” avec une courte description du problème doit être ajouté à la page donnés du greffon. Cela créera une boîte d'avertissement rouge et retirera le greffon de la liste principale des extensions.

Une fois le problème corrigé et une nouvelle version réalisée, ce champ doit être supprimé à nouveau.

Crédits

fr/devel/security.txt · Dernière modification : 2020-08-16 09:39 de Digitalin

Sauf mention contraire, le contenu de ce wiki est placé sous les termes de la licence suivante : CC Attribution-Share Alike 4.0 International
CC Attribution-Share Alike 4.0 International Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki