HTML, chmod, conteneurs et cron
Le raisonnement derrière quatre utilitaires : pourquoi un éditeur HTML a besoin d'une liste blanche et d'un bac à sable, pourquoi le S majuscule dans une chaîne chmod est important, ce qu'une commande d'exécution Docker ne peut pas exprimer dans la composition et les deux règles cron qui attrapent tout le monde.
L'éditeur HTML : une liste blanche, pas un filtre
L'éditeur produit du HTML, et le HTML provenant d'une zone de texte est le vecteur d'injection le plus ancien qui existe. Deux questions différentes se confondent ici, il vaut donc la peine de les séparer. La première est "cet éditeur peut-il être amené à émettre un balisage qui exécute du code dans la page qui l'affiche ?" La seconde est "est-ce un moyen sûr de nettoyer le HTML hostile d'une source non fiable ?" Cet outil répond oui à la première et non à la seconde, et il l'indique sur le panneau plutôt que de vous laisser supposer le contraire.
Le mécanisme est une liste verte. Une liste d'éléments est autorisée ; tous les autres éléments sont déballés, donc son texte survit et pas sa balise. Une liste d'attributs est autorisée par élément ; tout le reste est supprimé, ce qui rend chaque gestionnaire d'événements impossible plutôt que simplement bloqué. Les noms d'attribut sont en minuscules avant ce test, donc oNeRrOr et ONERROR sont le même nom rejeté que onerror. Les éléments dont le contenu est traité par l'analyseur HTML comme du texte brut (script, style, zone de texte, iframe, titre) sont supprimés avec leur contenu, car leur déballage collerait la source du script dans le document sous forme de balisage.
Les adresses de liens reçoivent leur propre contrôle. La valeur est entity-decoded et dépourvue d'espaces et de caractères de contrôle avant la lecture de son schéma, car c'est ce que fait un navigateur lorsqu'il navigue : javascript:alert(1) et jav ascript:alert(1) atteignent tous deux le même endroit. Seules les adresses http, https, mailto, tel, ftp et relatives survivent. Une référence de caractère que l'outil ne peut pas résoudre - : est le classique - entraîne le refus de l'adresse entière plutôt que sa transmission, car un filtre qui comprend moins l'entrée que le navigateur est un filtre avec un trou.
Il n'y a pas de bouton image et img ne figure pas sur la liste verte. Une balise d'image autorisée est une demande sortante provenant de l'endroit où le document aboutit et une surface d'erreur. Pour un éditeur qui produit de la prose, cela ne vaut pas non plus la peine.
La défense qui ne dépend pas de la perfection de tout cela est l’aperçu. Il s'affiche dans une iframe avec un attribut sandbox qui n'accorde rien du tout : pas de scripts, pas de formulaires, pas d'accès de même origine. Si une charge utile survivait à la liste autorisée, le navigateur refuserait toujours de l'exécuter à cet endroit. Il s’agit d’une garantie structurelle plutôt que d’une promesse concernant notre code.
La limitation honnête : il s’agit d’un désinfectant basé sur des chaînes, pas d’un analyseur HTML5 complet. Les différentiels des analyseurs – les entrées dans lesquelles un navigateur construit un arbre différent de celui de ce tokeniseur – sont la faiblesse connue de chaque désinfectant construit de cette façon. Pour la sortie que vous générez vous-même dans cet éditeur, c'est très bien. Pour nettoyer le HTML provenant d'un inconnu, utilisez un désinfectant exécuté sur un véritable analyseur, sur un serveur que vous contrôlez.
Chmod : la majuscule est tout le message
Un mode de fichier Unix est composé de douze bits : trois bits d'autorisation pour chacun des propriétaires, groupes et autres, plus setuid, setgid et le bit collant. La forme octale est une lecture directe de ces bits, c'est pourquoi 4 + 2 + 1 = 7 signifie lire, écrire et exécuter.
La forme symbolique imprimée par ls est celle où les bits spéciaux deviennent intéressants, car ils n'ont pas leur propre colonne. setuid remplace le caractère d'exécution du propriétaire, setgid remplace le caractère d'exécution du groupe et sticky remplace l'autre caractère d'exécution. La lettre est en minuscule lorsque le bit d'exécution sous-jacent est également défini et en MAJUSCULE lorsqu'il ne l'est pas.
Donc 4755 est rwsr-xr-x — un programme setuid qui peut être exécuté — tandis que 4644 est rwSr--r--, un fichier setuid que personne ne peut exécuter. Le S majuscule est le système qui vous indique que le mors est inerte, et c'est presque toujours une erreur plutôt qu'un choix. La même chose s'applique à 1644, qui affiche rw-r--r-T : un bit collant sur un fichier normal où l'autre bit d'exécution est clair, ce qui sur un noyau moderne ne fait précisément rien.
Deux autres distinctions qui méritent d’être maintenues. La chaîne de neuf caractères ls imprimée n'est pas l'argument pris par chmod : chmod veut une liste d'affectations telle que u=rwx,g=rx,o=rx,u+s. Et les mêmes bits signifient des choses différentes sur un répertoire que sur un fichier - exécuter signifie "peut entrer et parcourir", setgid signifie "les nouveaux fichiers héritent de ce groupe", et le bit collant signifie "n'importe qui peut créer, seul le propriétaire peut supprimer", ce qui est la raison pour laquelle /tmp est 1777.
docker run to composer : analyse et ce qui n'est pas converti
Le convertisseur divise la commande avec un tokeniser prenant en charge les guillemets écrit pour cet outil. Rien n'est exécuté, évalué ou remis à un shell. Une commande contenant des guillemets, $(...) ou un point-virgule est lue sous forme de caractères littéraux, car la seule chose que cet outil fait avec votre entrée est de la lire.
La plupart des indicateurs sont mappés proprement : les ports, les volumes, l'environnement, les étiquettes, la politique de redémarrage, les capacités, les vérifications de l'état, les limites de ressources, le DNS et les hôtes supplémentaires ont tous des clés de composition ayant la même signification. Les volumes nommés et les réseaux définis par l'utilisateur nécessitent une déclaration de niveau supérieur ainsi que la référence de service, de sorte que la sortie en comporte une - avec external: true sur les réseaux, car une exécution de docker réseau pourrait se joindre à une exécution qui existait déjà.
Certains indicateurs n'ont pas d'équivalent dans la composition, et c'est là que les convertisseurs échouent généralement silencieusement. --rm n'est pas une propriété de service : un service de composition n'est pas supprimé à sa fermeture. -d décrit comment vous avez appelé la CLI, et non ce qu'est le service. --link est hérité, --mount nécessite un formulaire long que cet outil n'écrit pas, --gpus dépend de votre pilote. Chacun d'entre eux produit un avertissement nommé au lieu de disparaître. Un indicateur inconnu produit également un avertissement et est traité comme ne prenant aucune valeur, car deviner qu'il en a fallu une transformerait le nom de votre image en argument et produirait un fichier erroné en toute confiance.
La sortie ne comporte aucune version de niveau supérieur : clé. Compose v2 l'ignore et les versions actuelles en avertissent ; il est obsolète depuis que la spécification Compose a remplacé les anciennes versions de format de fichier.
Citer n’est pas cosmétique. Un mappage de port écrit sous la forme 8080:80 sans guillemets est lu comme un nombre par les analyseurs YAML 1.1, et oui, non, on et off sont des booléens dans le même dialecte. Tout ce qui pourrait être mal interprété est cité ; tout ce qui se lit proprement sous forme de chaîne est laissé seul, le fichier reste donc lisible.
Cron : deux règles qui accrochent tout le monde
La première est la règle du jour. Lorsque le jour du mois et le jour de la semaine sont définis sur autre chose que *, cron exécute le travail lorsque SOIT correspond, et non lorsque les deux correspondent. Donc 0 0 13 * 5 signifie « minuit le 13 et minuit tous les vendredis », soit environ cinq fois par mois, et non « vendredi 13 », soit une ou deux fois par an. Le générateur avertit chaque fois que les deux champs sont restreints et la phrase qu'il écrit indique « ou » plutôt que « et ».
Le second est le fuseau horaire. Cron utilise la zone de la machine sur laquelle il s'exécute, qui est souvent l'UTC sur un serveur et presque jamais la zone de la personne qui écrit la crontab. L'aperçu de la prochaine exécution demande donc quelle zone utiliser plutôt que de supposer la vôtre. Les heures sont calculées comme des heures d'horloge murale dans cette zone, de sorte qu'une tâche quotidienne reste à la même heure locale lors d'un changement d'heure d'été plutôt que de dériver d'une heure - et une heure locale qui n'existe pas, dans l'heure sautée chaque printemps, est exclue de la liste, car cron ne fonctionnera pas non plus à ce moment-là.
La syntaxe elle-même est petite : une étoile, un nombre, une plage a-b, une liste a,b,c, une étape */n ou a-b/n, et les noms de mois et de jour JAN-DEC et SUN-SAT. 0 et 7 signifient dimanche. Une valeur simple avec un pas, telle que 5/15 dans le champ des minutes, signifie "de 5 à la fin de la plage, tous les 15", qui correspond aux minutes 5, 20, 35 et 50.
La validation est volontairement stricte. 60 * * * * est refusé car les minutes s'arrêtent à 59 ; * * * * 8 est refusé car le champ jour s'arrête à 7 ; */0 * * * * est refusé car un pas de zéro ne correspond à rien. Six champs signifient généralement une expression Quartz ou systemd dont le premier champ est constitué de secondes, donc l'erreur indique cela au lieu de seulement compter. Un planning qui est syntaxiquement valide mais ne peut jamais s'exécuter — 0 0 30 2 * demande le 30 février — est accepté et signalé, car le refuser serait une erreur et garder le silence serait pire.
Qu'arrive-t-il à ce que vous collez
- Chaque conversion, hachage, décodage et différence s'exécute dans l'onglet de votre navigateur. Aucune entrée n'est téléchargée, enregistrée ou stockée sur un serveur, car aucun serveur n'est impliqué une fois la page chargée.
- Les hachages proviennent de la propre implémentation Web Crypto du navigateur et les UUID de son générateur aléatoire cryptographiquement sécurisé. Ni l’un ni l’autre n’implique un appel réseau.
- Rien de ce que vous tapez n’est écrit dans le stockage local ou dans un cookie. Le rechargement de la page la supprime ; la fermeture de l'onglet le supprime.
- Les analyses à l'échelle du site s'exécutent uniquement sur l'hôte de production canonique configuré et sont divulguées dans la politique de confidentialité ; les hôtes locaux et de prévisualisation le refusent. Les valeurs collées, les jetons, les URL et le contenu des fichiers sont exclus des propres événements d'analyse de ToolAcre. La publicité est désactivée dans la configuration actuelle.
- Cela dit : un JWT ou une clé API est un identifiant en direct. La bonne habitude est de ne jamais en coller un dans une page Web que vous n’avez pas écrite, aussi dignes de confiance que ses affirmations – y compris celle-ci.
Questions
Puis-je coller du HTML hostile dans l’éditeur pour le nettoyer ?
Vous pouvez le coller, et rien ne s'exécutera : le gestionnaire de collage nettoie la charge utile du presse-papiers avant que quoi que ce soit ne soit inséré, et l'aperçu est une iframe en bac à sable sans scripts d'autorisation. Mais n'utilisez pas le résultat comme contrôle de sécurité pour une entrée non fiable. Il s'agit d'une liste d'autorisation basée sur des chaînes pour la propre sortie d'un éditeur, et non d'un filtre XSS à usage général, et l'analyseur d'un navigateur peut atteindre une arborescence différente de celle d'un tokeniseur comme celui-ci. Pour le contenu non fiable, nettoyez sur un serveur avec un véritable analyseur HTML5.
Pourquoi l'éditeur supprime-t-il mes images et mes tableaux ?
Parce qu'ils ne sont pas sur la liste verte. Les images sont une demande sortante et une surface d'erreur ; les tableaux sont tout simplement en dehors de ce à quoi sert cet éditeur. Leur contenu textuel survit, mais pas les balises. Il s'agit de la liste verte qui fonctionne plutôt que d'un bug, mais cela signifie que ce n'est pas le bon outil pour modifier un document existant complexe.
Pourquoi chmod 4644 affiche-t-il un S majuscule ?
Parce que setuid est défini et que le bit d'exécution du propriétaire ne l'est pas. La lettre majuscule signifie que le bit spécial n'a rien sur quoi agir : c'est un fichier setuid qui ne peut pas être exécuté. Un s minuscule signifie que les deux bits sont définis. La même règle vous donne S pour setgid et T pour le bit collant, et l'inverser est l'erreur la plus courante dans les calculateurs de mode.
Le convertisseur Docker exécute-t-il ma commande ?
Non, et ce n’est pas possible. La commande est divisée par un tokeniser qui comprend les citations et rien d'autre. Il n'y a pas d'évaluation, pas de shell, pas de processus enfant - la page n'a aucun moyen d'en démarrer un. Tout ce que vous collez reste dans l'onglet.
Pourquoi le convertisseur avertit-il au lieu de simplement supprimer un indicateur qu'il ne peut pas gérer ?
Parce qu'un fichier de composition qui fait silencieusement moins que la commande dont il provient est pire que pas de sortie du tout : vous le découvrez en production. Chaque drapeau qui n'est pas représenté est nommé et indique ce qu'il faut faire. Si vous ne voyez aucun avertissement, rien n’a été perdu.
Pourquoi les prochaines exécutions cron sont-elles différentes de celles de mon serveur ?
Presque toujours le fuseau horaire. Cron utilise la zone de la machine qui l'exécute ; l'aperçu utilise la zone que vous avez sélectionnée dans la liste déroulante. Définissez-le sur la zone de votre serveur – souvent UTC – et ils devraient être d’accord. L'autre candidat est la règle du jour : si le jour du mois et le jour de la semaine sont définis, cron s'exécute sur l'un ou l'autre, ce qui est plus souvent que ce que la plupart des gens envisagent.
Limites
- Le désinfectant HTML est une liste verte pour la propre sortie de cet éditeur, implémentée comme un tokeniseur de chaîne plutôt que comme un analyseur HTML5 complet. Il ne s'agit pas d'un filtre XSS à usage général et ne doit pas être utilisé comme tel.
- L'éditeur n'a pas d'images, de tableaux, de couleurs ou de contrôles de police, et aucun moyen de les ajouter : tout ce qui se trouve en dehors de la liste autorisée est supprimé.
- La surface d'édition utilise document.execCommand, qui est obsolète et n'a pas de remplacement implémenté. Les navigateurs le prennent toujours en charge ; le comportement diffère légèrement entre eux, en particulier autour de l'imbrication des listes.
- Le calculateur chmod couvre uniquement les douze bits d'autorisation. Les listes de contrôle d'accès, les attributs étendus, les contextes SELinux, l'arithmétique umask et les ACL Windows sont tous hors de portée.
- Le convertisseur Docker traduit une seule commande Docker Run en un seul service. Il ne lit pas les fichiers Docker, ne résout pas les images et ne peut pas exprimer --mount, --gpus, --device, --link ou --volumes-from ; chacun d'eux produit un avertissement nommé à la place.
- Les indicateurs que le convertisseur ne reconnaît pas sont traités comme ne prenant aucune valeur. Si un tel indicateur en prend un, la valeur sera mal lue - l'avertissement le dit, et la suppression de l'indicateur est la solution.
- Le générateur cron lit uniquement le format crontab à cinq champs. Expressions Quartz et systemd à six champs, @reboot et les expressions non standard L, W, # et ? les opérateurs sont refusés plutôt que devinés.
- Les heures de prochaine exécution proviennent de la propre base de données de fuseaux horaires du navigateur via Intl. Il s'agit d'un aperçu, pas d'une garantie : la machine exécutant cron peut avoir une zone différente, une version de base de données différente ou un démon qui n'était pas en cours d'exécution le moment venu.