Carnet Wiki

ConseilsSecurite

Cette page vise à recueillir et présenter les recommandations en matière d’injection de code dans SPIP.

Après la vague de piratages de mai 2023

Cf https://discuter.spip.net/t/fichiers-etranges-normal-ou-piratage/169909/10

-  spip_loader retire les anciennes versions des fichiers SPIP qui ne sont plus utilisées, mais ne s’occupe pas des fichiers qui n’ont jamais été SPIP. Et donc il ne retire pas des fichiers qui auraient été abusivement injectés sur le site.

(Nicod :) « Ça demande du temps à mettre en place et tester, et des compétences, et
un hébergement qui le permet, mais sur des sites sensibles, je règle les droits d’écriture de façon un peu stricte :
-  Apache n’a les droits d’écriture que sur /IMG, /local, /tmp et /config/fichiers, et pas plus (même pas /config pour les clés une fois qu’elles sont générées).
-  de plus, un .htaccess interdit l’exécution de tout fichier php dans ces répertoires là.
-  La mise à jour de SPIP et des plugins est faite uniquement par git, ce qui me permet de faire un git status pour vérifier si rien n’a été modifié. »

En cas de piratage
On peut essayer de repérer tous les fichiers ajoutés ou modifiés mais c’est fastidieux, les divers fichiers injectés peuvent changer de nom, et parfois ils font preuve de mimétisme environnemental puisque leur date est modifiée pour devenir la même que celle des fichiers légitimes.
b_b indique que le mieux c’est « un peu comme quand on fait une mise à jour majeure (cf Changer la version majeure de SPIP :
-  virer tous les dossiers de la dist (ecrire, prive, plugins-dist, etc),
-  ne garder que les dossiers qui contiennent des données perso (IMG, conf, plugins),
-  analyser ces dossier pour vérifier qu’ils sont safe,
-  relancer une install pour rétablir les dossiers et fichiers de la dist. »

Protégez le code php dans les squelettes

Cerdic : Si jamais on écrit du php dans un squelette :
-  TOUJOURS appliquer |texte_script a la fin d’un filtre qu’on injecte dans une variable PHP
-  TOUJOURS utiliser des simples quotes

$toto = '[(#TRUC|filtre_ce_que_tu_veux|texte_script)]’;

Protegez vos INCLURE

Dans le cas où le squelette inclus contient la balise #SELF ou #PAGINATION
et uniquement dans ce cas là, il est nécessaire de protéger self
dans l’appel à l’inclure, donc de mettre un argument du type {self=#SELF} dans la balise INCLURE.

Exemple :
<INCLURE{fond=inc-petition}{id_article}{self=#SELF}>

Notes :
-  ainsi on fonde l’url de cache du fragment inclu sur l’url de la page appelante
-  #PAGINATION en interne fait appel à #SELF

Refs : Fil sur spipdev, 5 et 6 Juin 06 (le début du thread étant là)


Accés restreint

Là c’est pas une protection contre l’injection de code donc c’est hors sujet.

Stéphane Laurent confie :
— « je fais généralement une première passe qui va definir les squelettes, css et gère la sécurité ... et derrière, j’ai une couche qui positionne les différents éléments inclus. Si ces éléments sont complexes, ils nécessitent eux même plusieurs inclures ... »

Refs : Stéphane Laurent sur spipdev, 7 Juin 06

je ne sais pas si c’est une reference, mais bon, voici un exemple complet avec les articles : j’ai des groupes de mot « techniques (je les préfixe par un _ pour pouvoir les exclure facilement des boucles mot) que j’affecte aux rubriques : _sq_squelette(un mot par squelette, par exemple »_toto« , »_titi"), _sq_securite (0,1 et 4, 0 etant reservé aux admins, 1 aux redacteurs et admins et 4 aux visiteurs authentifiés)

squelettes/article.html :

<BOUCLE_head(ARTICLES){statut=publie}{id_article}><?php 
 	global $auteur_session;
 	$statut="5";
 	if ($auteur_session['statut']=="") $statut="5";
 	else if ($auteur_session['statut']=="6forum") $statut="4";
 	else $statut=substr($auteur_session['statut'],0,1);
	$sq_squelette='';
	$sq_id_rubrique=0;
	$sq_securite='5'; 
?><BOUCLE_HIERARCHIE(HIERARCHIE){id_rubrique}>
 <BOUCLE_MOT_COULEUR_PARENT(MOTS){id_rubrique}{type=_sq_couleurs}{0,1}><?php 
    if($sq_couleur=='') $sq_couleur='[(#TITRE|texte_script)]'; 
?></BOUCLE_MOT_COULEUR_PARENT>
 <BOUCLE_MOT_TYPO_PARENT(MOTS){id_rubrique}{type=_sq_typographies}{0,1}><?php 
 	if($sq_typographie=='') $sq_typographie='[(#TITRE|texte_script)]'; 
?></BOUCLE_MOT_TYPO_PARENT>
 <BOUCLE_MOT_SQUELETTE_PARENT(MOTS){id_rubrique}{type=_sq_squelettes}{0,1}><?php
 	if($sq_squelette=='') {
 		$sq_squelette='[(#TITRE|texte_script)]'; 
 		$sq_id_rubrique=[(#ID_RUBRIQUE)]; 
	}
?></BOUCLE_MOT_SQUELETTE_PARENT>
 <BOUCLE_MOT_SECU_PARENT(MOTS){id_rubrique}{type=_sq_securites}{0,1}><?php 
 	if ('[(#TITRE|texte_script)]'<$sq_securite)
 			$sq_securite='[(#TITRE|texte_script)]';
 ?></BOUCLE_MOT_SECU_PARENT>
</BOUCLE_HIERARCHIE>
<BOUCLE_MOT_COULEUR(MOTS){id_rubrique}{type=_sq_securites}{0,1}><?php 
	$sq_couleur='[(#TITRE|texte_script)]'; 
?></BOUCLE_MOT_COULEUR>
<BOUCLE_MOT_TYPO(MOTS){id_rubrique}{type=_sq_typographies}{0,1}><?php 
 	$sq_typographie='[(#TITRE|texte_script)]'; 
?></BOUCLE_MOT_TYPO>
<BOUCLE_MOT_SQUELETTE(MOTS){id_rubrique}{type=_sq_squelettes}{0,1}><?php 
	$sq_squelette='[(#TITRE|texte_script)]'; 
		$sq_id_rubrique=[(#ID_RUBRIQUE)]; 
?></BOUCLE_MOT_SQUELETTE>
<BOUCLE_MOT_SECU(MOTS){id_rubrique}{type=_sq_securites}{0,1}><?php 
 	if ('[(#TITRE|texte_script)]'<$sq_securite)
 			$sq_securite='[(#TITRE|texte_script)]';
?></BOUCLE_MOT_SECU><?php 
if ($statut<=$sq_securite)
{	
	if($sq_couleur=='') $sq_couleur='defaut'; 
	if($sq_typographie=='') $sq_typographie='defaut';
	if($sq_squelette=='defaut') $sq_squelette='';
	$sq_squelette='article'.$sq_squelette; 
?><INCLURE(bloc_sq.php3){id_article}>
<?php 
} else {
?>
accès interdit
<?php 
}
?>
</BOUCLE_head>

Ce squelette va donc gérer la securité, et mettre en place les paramètres de squelette, couleur et typo qui seront passés à la feuille de style.

squelettes/bloc_sq.php3 :

$delais=3600;
//secu basique
if (strstr($sq_squelette, '..') 
OR preg_match(',^formulaire_,i', $sq_squelette) {
		die ("securité !");
}
else $fond = "_".$sq_squelette;
if ($contexte_inclus['bloc_delais']) $delais = $contexte_inclus['bloc_delais'];

$contexte_inclus['sq_typographie']=$sq_typographie;
$contexte_inclus['sq_couleur']=$sq_couleur;
$contexte_inclus['sq_id_rubrique']=$sq_id_rubrique;

include ("inc-public.php3");

le squelette correspondant au mot clé sera appelé (par defaut _article.html) et les parametres mis dans le contexte.

=> Attention, il faut empecher l’accès direct à ces squelettes et à bloc_sq.php3 (.htaccess) et en particulier, « blinder » page.php3, par exemple :

// Securite 
if (strstr($fond, '/')
OR preg_match(',^_,i', $fond)) 
OR preg_match(',^formulaire_,i', $fond)) {
	die ("Faut pas se gener");
}

On aura donc le squelette _article_toto.html appelé si on a affecté le mot _sq_squelettes:_toto à la rubrique ou plus haut dans la hierarchie
dans les squelettes _article, j’appelle :

<link rel="stylesheet" href="style.php3?sq_typographie=[(#ENV{sq_typographie,defaut})]&sq_couleur=[(#ENV{sq_couleur,defaut})]&id_rubrique=[(#ENV{id_rubrique})]&sq_id_rubrique=[(#ENV{sq_id_rubrique})]" type="text/css">

style.php3 appelant un squelette style.html.
J’ai donc une feuille de style calculée et mise en cache par rubrique.

- Mise à jour :14 juin 2023 à 10h54min