Pourquoi s'échapper si le_contenu n'est pas?

8

La fonction intégrée the_contentpasse par plusieurs filtres, mais n'échappe pas à la sortie. Il lui serait difficile de le faire, car HTML et même certains scripts doivent être autorisés.

Lors de la sortie, the_content semble passer par ces filtres (à partir de 5.0):

add_filter( 'the_content', 'do_blocks', 9 );
add_filter( 'the_content', 'wptexturize' );
add_filter( 'the_content', 'convert_smilies', 20 );
add_filter( 'the_content', 'wpautop' );
add_filter( 'the_content', 'shortcode_unautop' );
add_filter( 'the_content', 'prepend_attachment' );
add_filter( 'the_content', 'wp_make_content_images_responsive' );

(and)

add_filter( 'the_content', 'capital_P_dangit' );
add_filter( 'the_content', 'do_shortcode' );

Il remplace également une simple chaîne:

$content = str_replace( ']]>', ']]>', $content );

Et puis get_the_content fait un tout petit peu de traitement lié au lien "more" et un bug avec les langues étrangères.

Aucun de ceux-ci n'empêche l'injection de script XSS, non?

Lors de l'enregistrement, les données sont filtrées via wp_kses_post. Mais comme c'est un processus coûteux, je comprends pourquoi il n'est pas utilisé en sortie.

La règle d'or pour l'échappement WordPress est que tout doit être échappé, indépendamment de l'assainissement des entrées, et le plus récemment possible. J'ai lu plusieurs articles disant cela, car la base de données ne doit pas être considérée comme une source de confiance.

Mais pour les raisons ci-dessus, the_content ne suit pas cela. Les thèmes principaux (par exemple TwentyNineteen) n'ajoutent pas non plus d'échappement supplémentaire à la sortie.

Alors ... pourquoi est-ce que ça aide quelque chose à s'échapper ailleurs? Si j'étais un hacker ayant accès à la base de données, ne devrais-je pas simplement ajouter mon code au contenu d'une publication?

tmdesigned
la source
Vous avez oubliéwp_kses_post
Tom J Nowell
Il passe par wp_kses_post en sortie? Où?
tmdesigned

Réponses:

10

Si j'étais un hacker ayant accès à la base de données, ne devrais-je pas simplement ajouter mon code au contenu d'une publication?

Si vous avez accès à la base de données, il est probable que vous disposiez d'un accès suffisant pour que l'évasion ne vous arrête pas. S'échapper ne vous aidera pas si vous avez été piraté. Ce n'est pas censé le faire. Il y a d'autres raisons de s'échapper. Les deux principaux auxquels je peux penser sont:

Pour gérer les entrées non désinfectées

Le contenu des articles WordPress est nettoyé lors de son enregistrement, mais tout le reste ne l'est pas. Le contenu transmis via une chaîne de requête dans l'URL n'est pas filtré, par exemple. Le contenu des fichiers de traduction n'est pas non plus nécessairement. Ces deux sources de contenu n'ont rien à voir avec le site compromis. Le texte et le contenu traduisibles extraits de l'URL doivent donc être échappés.

Pour empêcher les utilisateurs de rompre accidentellement le balisage

S'échapper n'est pas seulement pour la sécurité. Vous en avez également besoin pour empêcher les utilisateurs de casser accidentellement le balisage de leur site. Par exemple, si l'utilisateur qui place des guillemets ou des >symboles dans du contenu de votre plug-in rompt le balisage, vous devez échapper à cette sortie. Vous ne voulez pas être trop agressif dans le nettoyage de l'entrée, car il y a des raisons parfaitement valables qu'un utilisateur veuille utiliser ces caractères.


«S'échapper, ce n'est pas seulement se protéger des méchants. Cela rend simplement notre logiciel durable. Contre les mauvaises entrées aléatoires, contre les entrées malveillantes ou contre le mauvais temps. »

Cela vient des directives WordPress VIP sur l'évasion . Il a beaucoup plus à dire à ce sujet, et vous devriez le lire.

Jacob Peattie
la source
Merci, c'est utile. J'avais lu un article sur VIP sur l'évasion et l'auteur a spécifiquement mentionné l'idée que quelqu'un ait accédé à la base de données mais pas au serveur. Cependant, je pense que votre raisonnement sur ce point est plus logique. Et, je suppose, parfois vous échappez du contenu vulnérable de la base de données même sans que quelqu'un ait eu un accès complet à la base de données, c'est-à-dire via un plugin ou même juste un commentaire.
tmdesigned
9

Je suis en fait un ingénieur chez VIP qui fait beaucoup de révision de code :) Je signale beaucoup d'échappements manquants.

mais n'échappe pas à la sortie

Pas tout à fait, il ne s'échappe pas en sortie, ce qui surprend la plupart des gens. En effet, si vous êtes un super administrateur, vous en avez la unfiltered_htmlcapacité, il ne peut donc pas s'échapper en sortie. Au lieu de cela, il l'exécute wp_kses_posten entrée. Idéalement, vous supprimeriez cette capacité.

Voici l'implémentation à l'heure actuelle:

function the_content( $more_link_text = null, $strip_teaser = false ) {
    $content = get_the_content( $more_link_text, $strip_teaser );

    /**
     * Filters the post content.
     *
     * @since 0.71
     *
     * @param string $content Content of the current post.
     */
    $content = apply_filters( 'the_content', $content );
    $content = str_replace( ']]>', ']]>', $content );
    echo $content;
}

Le mécanisme idéal pour échapper à tout ce qui passe à travers le the_contentfiltre est d'autre part:

echo apply_filters( 'the_content', wp_kses_post( $content ) );

De cette façon, nous sécurisons le contenu, puis le passons à travers le filtre, en évitant que les intégrations, etc. soient supprimées.

Alors pourquoi s'échapper

Le point de fuite est de générer du HTML valide, la sécurité supplémentaire qu'il offre n'est qu'un bel effet secondaire.

Pour empêcher les utilisateurs de rompre accidentellement le balisage

Il y a de nombreuses raisons de s'échapper, mais fondamentalement, vous faites respecter les attentes. Prenez le code suivant:

<a href="<?=$url?>">

Nous nous attendons $urlà contenir une URL adaptée à un hrefattribut, mais que faire si ce n'est pas le cas? Eh bien, pourquoi le laisser au hasard, permet de le faire respecter:

<a href="<?=esc_url( $url )?>">

Ce sera désormais toujours une URL. Peu importe si un pirate met une image $urldedans, si un utilisateur tape dans le mauvais champ, ou s'il y a un script malveillant. Ce sera toujours une URL valide, car nous avons dit que ce serait une URL. Bien sûr, il peut s'agir d'une URL très étrange, mais elle répondra toujours à l'attente qu'une URL soit là. C'est très pratique, que ce soit pour la validation du balisage, pour la sécurité, etc.

Cela dit, l'évasion n'est pas une validation, l'évasion n'est pas une désinfection. Ce sont des étapes distinctes qui se produisent à différents moments du cycle de vie. S'échapper oblige les choses à répondre aux attentes, même si cela les empêche de le faire.

Parfois, j'aime penser à m'évader comme l'un de ces jeux japonais avec le mur de mousse géant avec la découpe. Les concurrents doivent s'adapter à la forme du chien ou ils sont jetés, seulement pour nos fins il y a des lasers et des couteaux autour du trou. Tout ce qui restera à la fin sera en forme de chien, et il sera impitoyable et strict si vous n'êtes pas déjà en forme de chien.

Rappelles toi:

  • désinfecter tôt
  • valider tôt
  • s'échapper tard
  • s'échapper souvent

La sécurité est une étape multiple, un oignon multicouche de défenses, l'évasion est l'une des couches externes de défense en sortie. Il peut perturber le code d'attaque sur un site compromis, le rendant inutile, contrecarrer les exploits ouverts et s'assurer que votre client ne casse pas un site en mettant des balises dans un champ qu'il ne devrait pas. Ce n'est pas un substitut pour les autres choses, et c'est de loin l'outil de sécurité le plus sous-utilisé dans le manuel du développeur.

Quant à savoir pourquoi s'échapper si ce the_contentn'est pas le cas? Si vous avez une inondation à venir et 5 trous dans un mur, mais seulement le temps de réparer 3, haussez-vous les épaules et n'en réparez-vous pas? Ou atténuez-vous le risque et réduisez-vous la zone d'attaque?

Je peux peut-être aider à réparer ces 2 derniers trous avec cet extrait:

add_filter( 'the_content' function( $content ) {
    return wp_kses_post( $content );
}, PHP_INT_MAX + 1 );

Ici, nous fixons la priorité au nombre le plus élevé possible en PHP, puis ajoutons 1 pour qu'il déborde au plus petit nombre possible qui peut être représenté. De cette façon, tous les appels à the_contentéchapperont à la valeur avant tout autre filtre. De cette façon, les intégrations, etc. fonctionnent toujours, mais les utilisateurs ne peuvent pas s'introduire dans du code HTML dangereux via la base de données. En outre, envisagez de supprimer la unfiltered_htmlcapacité de tous les rôles

Tom J Nowell
la source
1
Merci pour la perspective supplémentaire. J'avais en fait lu votre message sur ce sujet sur votre site et je me demandais si vous auriez quelque chose à ajouter.
tmdesigned
4

Le point de fuite est de générer du HTML valide, la sécurité supplémentaire qu'il offre n'est qu'un bel effet secondaire.

Les filtres appliqués sur le contenu génèrent un code HTML valide à partir de quelque chose qui est un mélange de code HTML et d'autres textes qui ont une autre syntaxe comme les shortcodes. Le fait qu'une partie du contenu soit déjà HTML valide empêche d'appliquer l'échappement sur tout le contenu.

Quant aux ksesfonctions liées, vous ne pouvez pas les appliquer principalement parce que vous n'avez pas assez de contexte pour savoir laquelle utiliser. Par exemple, il peut y avoir un processus qui utilise le the_contentfiltre pour ajouter du JS au contenu de la publication.Le noyau ne peut donc pas deviner sur la base de choses comme l'auteur de la publication si le JS est légitime ou non.

Alors ... pourquoi est-ce que ça aide quelque chose à s'échapper ailleurs? Si j'étais un hacker ayant accès à la base de données, ne devrais-je pas simplement ajouter mon code au contenu d'une publication?

Encore une fois, l'échappement sert à générer du HTML valide. D'un POV de sécurité, ce n'est pas que l'échappement apporte la sécurité, mais qu'un code qui a du mal à s'échapper doit être suspect car il pourrait être plus facile à exploiter. Par exemple, la façon dont Core utilise _eet «__» pour les traductions signifie que toute personne qui peut vous convaincre d'installer une traduction non officielle peut être en mesure d'ajouter du matériel pour détecter JS dans le fichier de traduction et pirater votre site. C'est un bon exemple de "fais ce que je dis et non ce que je fais".

Mark Kaplun
la source
Merci, Mark, pour la perspective supplémentaire.
tmdesigned
2

Si j'étais un hacker ayant accès à la base de données, ne devrais-je pas simplement ajouter mon code au contenu d'une publication?

Je pense que votre question se répond d'elle-même. Si vous étiez un hacker ayant accès à la base de données, vous avez déjà obtenu l'accès dont vous avez besoin. L'échappement de sortie ne change rien à cela.

La raison de l'échappement de la sortie est d'évaluer les données non fiables pour éviter que le pirate n'obtienne cet accès en premier lieu.

butlerblog
la source
Merci pour votre réponse. Je pense que je suis devenu trop concentré sur l'idée d'empêcher un pirate qui m'a manqué la forêt pour les arbres.
tmdesigned