Comment j’ai réparé l’article sur la sécurisation SSH

closeCet article a été publié il y a 7 ans 11 mois 1 jour, il est donc possible qu’il ne soit plus à jour. Les informations proposées sont donc peut-être expirées.

Vous avez été plusieurs à me remonter l’information par différents canaux, la première partie de la série sur la sécurisation d’un serveur Linux était HS, et même son affichage dans les pages de catégories ou de recherche flinguait l’affichage du site (allant de l’affichage partiel à la page blanche). J’ai cherché longtemps, et j’ai souffert pour trouver d’où venait le problème. Reste que même si j’ai résolu l’affaire, je peux pour l’instant seulement l’expliquer partiellement, et non pas dans les moindres détails.

Première étape : la base de données

Comme au travail un collègue a eu un problème avec des champs mal remplis (tenter de convertir une date « NULL » ne fonctionne pas en PHP, qu’on se le dise), je me suis dit que ça pouvait venir de là. Sachant que l’édition de l’article fonctionne, j’ai filtré le contenu pour ne garder que les autres champs :

Bon, rien de choquant, ça ne vient pas de là. Je me rabats ensuite sur la table wp_postmeta :

Gné ? Petite recherche, dsq_thread_id est un vestige de Disqus, petit sagouin qui ne fait pas le ménage correctement (spoiler : il est loin d’être le seul à laisser du bordel en partant). On le vire :

Quand même. Mais malheureusement, rien de neuf sous le soleil, au moins ai-je nettoyé un peu la base de données. Pour info, je suis toujours en mode DEBUG au niveau du WordPress, mais aucun message ou presque ne vient me titiller les yeux, à part quelques messages de déprécation de la part d’une fonction du cœur de WordPress (depuis PHP 5.3, les gars, sérieux ?), et du plugin d’insert de code (celui pour les boutons sociaux). Merci PHP 7 🙂

J’essaie malgré tout de récupérer plus de messages en ajoutant une ligne dans mon fichier de conf du pool FPM :

Toujours rien (remarquez au passage l’héritage d’ISPConfig). PHP n’étant pas plus bavard, je change mon fusil d’épaule, et laisse pousser un peu la barbe.

Deuxième étape : le microscope géant

En effet, je me suis rabattu sur un outil qui commence à me servir pas mal au travail, strace. Il faut vraiment se faire la main dessus pour comprendre à quel point il peut vous sauver la vie. Et là, c’était pas loin. Je remercie une fois de plus Djerfy à qui je dois cette routine :

Euh, pardon ? Autant les fois précédentes, il fallait arrêter le strace à la main, autant là, il m’a carrément pété dans les pattes. Assez violent, et ça explique les messages d’erreurs d’Nginx qui dit que la communication a été rompue (sans plus de détails). J’ai donc un fichier /tmp/strace_fpm.log.3505 à analyser, et il fait plus 12Mo le bougre (ls -lh l’arrondit même à 13). Vu que le process FPM a été flingué, je me rend directement à la fin du fichier pour tenter de savoir pourquoi il s’est terminé :

Wait, WHAT ? J’apprends sur la bible StackOverflow qu’un SIGSEGV, déjà pas vraiment un signal qu’on aime voir (essaie d’aller faire des crasses dans des zones mémoires où il n’a pas le droit d’aller, ce que le PROT_READ|PROT_WRITE|PROT_EXEC semble d’ailleurs indiquer), dans le contexte qui nous intéresse veut dire que PHP plante à cause d’une récursion infinie. Mais que diable PHP essaie donc de faire là, qu’est-ce qui peut bien l’y pousser, et surtout pourquoi uniquement avec cet article-là ?

Troisième étape : le contenu

Retour au back-office de WordPress, et concentrons-nous sur le contenu de l’article, puisque c’est au final la seule véritable variable de l’équation. J’avais déjà regardé de près si des caractères un peu bizarres avaient pu se glisser dans l’histoire, mais rien de probant sur l’instant (raison pour laquelle j’avais laissé le contenu de côté au début de l’enquête). Tentative désespérée en guise de confirmation : je vide le contenu de l’article. La page s’affiche bien entièrement, mais sans le contenu puisqu’il n’y en a plus.

Poisse. L’article est assez long, entrecoupé de nombreux blocs de codes contenant aussi bien des commandes que des extraits de fichiers de configuration. J’entreprends alors de recopier l’article paragraphe par paragraphe pour tenter de localiser le morceau problématique. Et je finis par tomber sur THE bloc problématique : le détail du « jail » sshd.conf. Question, pourquoi lui en particulier ? Et surtout, pourquoi ça fonctionnait avant, quand est-ce qu’il a décidé de faire chier son monde (j’ai des mails qui remontent déjà à Fevrier) ? Quelque chose a-t-il été modifié sans prévenir (à la faveur d’une migration quelconque, un mysqldump mal paramétré ?) ? Beaucoup de questions donc, et au final, une première partie de réponse assez courte.

La solution, c’est simple comme un coup de clic

En réfléchissant bien ce paragraphe fautif est assez imbuvable en termes d’expressions régulières, et bien des parseurs se casseraient les dents dessus. Une réflexion que vient confirmer un test d’Arowan en parallèle, à qui j’ai transmis le contenu de l’article pour qu’il l’essaie sur son blog. Ça semble fonctionner chez lui, mais je constate qu’a priori il n’a pas de coloration syntaxique. S’en suit le petit échange sur Twitter :

crayon_testJ’ai donc trouvé le couple coupable : Crayon Syntax Highlighter (au demeurant très bon plugin de coloration syntaxique, que m’avais recommandé Julien Hommet d’ailleurs), et mon extrait de configuration. En effet, pour rappel voilà à quoi ressemble ce bloc :

Vous les sentez les expressions regulières de l’enfer ? Donc comme pour vous l’afficher aujourd’hui, j’ai simplement usé d’un simple clic pour cocher une case :

crayon_dont_highlightCe « Don’t Highlight » indique au plugin de ne pas interpréter le fichier. Et après avoir recollé le reste de l’article, je peux confirmer que c’était le seul fautif. L’article est donc de retour en ligne, je peux souffler et prévenir par mail les personnes qui m’avaient remonté le souci. Sur Twitter, les gens ont pu suivre dimanche en temps réel les évolutions.

RCA : pas complet

La cause profonde, je la laisse aux plus furieux et barbus d’entre vous, quand je vois la liste de regex, pas surprenant que le parsing foire. Mais malgré tout, ça reste surprenant puisque dans mon environnement Docker de test (monté et raconté à l’occasion d’un billet d’humeur), avec du PHP 5.6, ça ne le fait pas. J’imagine donc une évolution dans certaines fonctions liées aux chaines de caractères, typiquement une fonction preg_match() qui pourrait se voir « violée » par une telle syntaxe. Evolutions qui ne plaisent pas à tous les parseurs de code en manque d’attention. L’utilisation plus poussée du JIT pourrait aussi être une piste à considérer dans ce contexte.

Malheureusment, à voir le dépôt Github le développement du plugin n’est plus très actif, j’hésite donc à remonter le bug. Et je ne suis pas assez bon en PHP pour me refaire la lecture du plugin et tenter de corriger le comportement. Mais le plantage du thread FPM peut déjà expliquer l’absence de message d’erreur remonté dans les logs PHP.

Aussi, je n’ai pas non plus le niveau pour aller tâter du GDB. Alors si vous avez du temps à perdre, n’hésitez pas, essayez par vous-même. Honnêtement, je garde cette enquête en tête, mais là, j’ai juste envie de souffler un peu. En écoutant du BabyMetal 😀

7 Commentaires
Le plus ancien
Le plus récent
Commentaires en ligne
Afficher tous les commentaires
Dominique HAAS
27/04/2016 19:07

Coucou,
Concernant le plugin Crayon Syntax Highlighter, je l’avais aussi utilisé au début sur mon blog Mercure News (https://mercu.re). Mais j’ai très vite changé, car comme tu l’as dit, il n’est pas maintenu. Un autre problème que j’avais avec était qu’il ne produit pas du code valide W3C. J’ai un article en brouillon sur mon blog qui parle de PrismJS (http://prismjs.com/) et de comment l’intégrer dans son blog wordpress. Je vais le finir au plus vite et le programmer :).

Neros
27/04/2016 21:31

N’hésite pas à remonter un bug ! Toujours rapporter un bug !
En plus, son développement est bien actif: dernière version il y a 14 jours et 35 commits depuis le début de l’année.
Il est même plutôt vivant.

Julien HOMMET - CZS
28/04/2016 08:36

Intéressant de connaître toutes les étapes qui t’ont permis de trouver / corriger le pb !
C’était donc le plugin qui impactait tes articles – ce qui est étonnant, c’est que tu avais quelques fois un problème pour l’affichage des pages d’archives… peut-être est-ce était lié, du fait que le thread fpm se plantait ?

Dans tous les cas, tu as réussi, bravo 🙂

Cyril Chaboisseau
Cyril Chaboisseau
28/04/2016 09:19

salut, pour revenir sur la commande strace (inspirée de Djerfy), moi aussi j’avais eu aussi besoin de tracer les appels systèmes relatifs à tout ce qui concerne les fichiers (open/close/*stat/..) de nginx, et pour ça j’avais utiliser la ligne de commande suivante : ps aux|egrep ‘(nginx|php|fpm|cgi)’|grep -v ‘grep -E’|cut -c10-14|xargs -n 1 echo -n ‘ -p’ le tout passé à strace qui est non seulement bien crade comme syntaxe (beaucoup de pipe assez illisibles), mais surtout avec un découpage risqué si le nom du compte qui lance la commande a plus de 8 caractères (bon, en général ça tourne sous… Lire la suite »

Cyril Chaboisseau
Cyril Chaboisseau
28/04/2016 12:40
Répondre à  Cyril Chaboisseau

oups, pour la 2e ligne il fallait lire :

[…]
au final, j’ai pu changer tout ça en lisant un peu le man avec la commande suivante (et 1 seule pipe) :
ps -C fcgiwrap -C nginx -C php-fpm7.0 -o pid=|xargs -n 1 echo -n ‘ -p’
et voici…

(désolé pour l’erreur de copier/coller)

Cascador
Cascador
29/04/2016 10:01

Très sympa, merci du partage, j’ai appris des trucs !

Tcho !

xhark
06/05/2016 01:20

Intéressant, je crois moi aussi que j’ai déjà eu ça, je testerai merci !