Browse Source

Refactoring de la gestion du _oups dans le formulaire_editer_liens :

- utiliser une fonction lien_gerer__oups() pour stocker/set/reset/request la valeur du oups, ce qui permet de la stocker dans une static pour la passer de traiter() à charger() plutot que dans une request()
- le oups sont accompagnes de l'id_auteur/time/arguments du formulaires, et encodés/signés via la fonction encoder_contexte_ajax() qui utilise le secret_du_site()
- au decodage, on verifie que id_auteur/time/arguments sont bon et on verifie egalement la structure des donnees dans le oups en vidant tout ce qui est suspect

Refs: spip-team/securite#4836
remotes/checkIfPRContentChanged-1663684980776890357/master
Cerdic 2 months ago committed by Gitea
parent
commit
07695e6f35
  1. 1
      CHANGELOG.md
  2. 137
      prive/formulaires/editer_liens.php

1
CHANGELOG.md

@ -4,6 +4,7 @@
### Security
- spip-team/securite#4836 Refactoring de la gestion du oups du formulaire editer_liens
- spip-team/securite#3724 #5150 Le core ne génère plus de champ htpass par défaut dans `spip_auteurs`. Utiliser le plugin Htpasswd https://git.spip.net/spip-contrib-extensions/htpasswd pour ce besoin.
### Added

137
prive/formulaires/editer_liens.php

@ -132,14 +132,7 @@ function formulaires_editer_liens_charger_dist($a, $b, $c, $options = []) {
$oups = '';
if ($editable) {
$oups = _request('_oups') ?? '';
if ($oups) {
if (json_decode(base64_decode($oups, true))) {
// on est bon, rien a faire
} else {
$oups = '';
}
}
$oups = lien_gerer__oups('editer_liens', 'hash');
}
$valeurs = [
'id' => "$table_source-$objet-$id_objet-$objet_lien", // identifiant unique pour les id du form
@ -232,12 +225,13 @@ function formulaires_editer_liens_traiter_dist($a, $b, $c, $options = []) {
include_spip('inc/autoriser');
if (autoriser('modifier', $objet, $id_objet)) {
// annuler les suppressions du coup d'avant !
// recuperer le oups du coup d'avant pour le propager à charger() si on ne fait rien par exemple
lien_gerer__oups('editer_liens','request');
// annuler les suppressions du coup d'avant ?
if (
_request('annuler_oups')
and $oups = _request('_oups')
and $oups = base64_decode($oups, true)
and $oups = json_decode($oups, true)
and $oups = lien_gerer__oups('editer_liens','get')
) {
if ($oups_objets = charger_fonction("editer_liens_oups_{$table_source}_{$objet}_{$objet_lien}", 'action', true)) {
$oups_objets($oups);
@ -253,7 +247,7 @@ function formulaires_editer_liens_traiter_dist($a, $b, $c, $options = []) {
}
}
# oups ne persiste que pour la derniere action, si suppression
set_request('_oups');
lien_gerer__oups('editer_liens','reset');
}
$supprimer = _request('supprimer_lien');
@ -315,7 +309,11 @@ function formulaires_editer_liens_traiter_dist($a, $b, $c, $options = []) {
}
}
}
set_request('_oups', $oups ? base64_encode(json_encode($oups)) : null);
if (!empty($oups)) {
lien_gerer__oups('editer_liens','set', $oups);
} else {
lien_gerer__oups('editer_liens','reset');
}
}
if ($ajouter) {
@ -344,7 +342,7 @@ function formulaires_editer_liens_traiter_dist($a, $b, $c, $options = []) {
# une suppression suivie d'un ajout dans le meme hit est un remplacement
# non annulable !
if ($ajout_ok) {
set_request('_oups');
lien_gerer__oups('editer_liens','reset');
}
}
@ -361,7 +359,7 @@ function formulaires_editer_liens_traiter_dist($a, $b, $c, $options = []) {
objet_qualifier_liens([$objet2 => $idl], [$objet1 => $ids], $qualif);
}
set_request('id_lien_ajoute', $ids);
set_request('_oups');
lien_gerer__oups('editer_liens','reset');
}
}
}
@ -511,3 +509,110 @@ function lien_ajouter_liaisons($objet_source, $ids, $objet_lien, $idl, $qualifs)
objet_associer([$objet_source => $ids], [$objet_lien => $idl]);
}
}
/**
* Fonction de regroupement pour gerer le _oups de façon sécurisée sans passer par une globale ni par une _request
* @param string $action
* @param array|null $valeur
* @return array|string|null
*/
function lien_gerer__oups(string $form, string $action, ?array $valeur = null) {
static $_oups_value;
switch ($action) {
case 'reset':
$res = (empty($_oups_value) ? false : true);
$_oups_value = null;
return $res;
case 'get':
return $_oups_value ?: null;
case 'set':
$_oups_value = $valeur;
return true;
case 'request':
$_oups_value = null;
if ($oups = _request('_oups')) {
include_spip('inc/filtres');
// on accepte uniquement une valeur signée
if ($oups = decoder_contexte_ajax($oups, $form)) {
if (!is_array($oups)
or empty($oups['id_auteur'])
or $oups['id_auteur'] !== $GLOBALS['visiteur_session']['id_auteur']
or empty($oups['time'])
or $oups['time'] < $_SERVER['REQUEST_TIME'] - 86400
or empty($oups['args'])
or $oups['args'] !== lien_gerer__oups_collecter_args($form, debug_backtrace(null, 5))
or empty($oups['oups_value'])) {
$oups = null;
}
else {
$oups = $oups['oups_value'];
// controler le contenu
foreach ($oups as $k => $oup) {
if (!is_array($oup)) {
unset($oups[$k]);
}
else {
foreach ($oup as $champ => $valeur) {
if (!is_scalar($champ)
or !is_scalar($valeur)
or preg_match(',\W,', $champ)
) {
unset($oups[$k][$champ]);
}
}
if (empty($oups[$k])) {
unset($oups[$k]);
}
}
}
}
$_oups_value = $oups;
return $_oups_value;
}
}
break;
case 'hash':
if (!$_oups_value) {
return '';
}
include_spip('inc/filtres');
$oups = [
'id_auteur' => $GLOBALS['visiteur_session']['id_auteur'] ?? 0,
'time' => strtotime(date('Y-m-d H:00:00')),
'args' => lien_gerer__oups_collecter_args($form, debug_backtrace(null, 5)),
'oups_value' => $_oups_value,
];
return encoder_contexte_ajax($oups, $form);
}
}
/**
* Collecter les args du form utilisant la fonction lien_gerer__oups()
* @param $trace
* @return false|float|int|mixed|Services_JSON_Error|string
*/
function lien_gerer__oups_collecter_args($form, $trace) {
$args = '';
if (!empty($trace)) {
do {
$t = array_shift($trace);
$function = $t['function'] ?? '';
if (strpos($function, 'formulaires_'. $form) === 0) {
if (isset($t['args'])) {
$args = json_encode($t['args']);
}
break;
}
}
while (count($trace));
}
return $args;
}

Loading…
Cancel
Save