Dépôt officiel du core SPIP Les plugins-dist faisant partie de la distribution SPIP sont présents dans https://git.spip.net/spip/[nom du plugin dist] https://www.spip.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

263 lines
8.5 KiB

<?php
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
7 years ago
* Copyright (c) 2001-2016 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
* Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
\***************************************************************************/
if (!defined('_ECRIRE_INC_VERSION')) return;
/**
* interface d'appel:
* - au moins un argument: retourne une URL ou un formulaire securises
* - sans argument: verifie la securite et retourne _request('arg'), ou exit.
*
* http://doc.spip.org/@inc_securiser_action_dist
*
* @param string $action
* @param string $arg
* @param string $redirect
* @param bool|int|string $mode
* -1 : renvoyer action, arg et hash sous forme de array()
* true ou false : renvoyer une url, avec &amp; (false) ou & (true)
* string : renvoyer un formulaire
* @param string|int $att
* id_auteur pour lequel generer l'action en mode url ou array()
* atributs du formulaire en mode formulaire
* @param bool $public
* @return array|string
*/
14 years ago
function inc_securiser_action_dist($action='', $arg='', $redirect="", $mode=false, $att='', $public=false)
{
if ($action)
return securiser_action_auteur($action, $arg, $redirect, $mode, $att, $public);
else {
$arg = _request('arg');
$hash = _request('hash');
$action = _request('action')?_request('action'):_request('formulaire_action');
if ($a = verifier_action_auteur("$action-$arg", $hash))
return $arg;
include_spip('inc/minipres');
echo minipres();
exit;
}
}
/**
* Attention: PHP applique urldecode sur $_GET mais pas sur $_POST
* cf http://fr.php.net/urldecode#48481
* http://doc.spip.org/@securiser_action_auteur
*
* @param string $action
* @param string $arg
* @param string $redirect
* @param bool|int|string $mode
* -1 : renvoyer action, arg et hash sous forme de array()
* true ou false : renvoyer une url, avec &amp; (false) ou & (true)
* string : renvoyer un formulaire
* @param string|int $att
* id_auteur pour lequel generer l'action en mode url ou array()
* atributs du formulaire en mode formulaire
* @param bool $public
* @return array|string
*/
function securiser_action_auteur($action, $arg, $redirect="", $mode=false, $att='', $public=false) {
// mode URL ou array
if (!is_string($mode)){
$hash = calculer_action_auteur("$action-$arg",is_numeric($att)?$att:null);
Résolution de #1510, cette double redirection d'action conduisant à plusieurs changements: * réintégration dans le script {{{../public.php}}} de tous les cas ne suivant pas le déroulement complet d'utilisation d'un squelette (action, CVT) afin de migrer tous les appels à {{{exit}}} de {{{public/assembler}}} dans le script initial (il en reste un, dans la fonction repérant un violation de sécurité CVT ça peut se justifier). * abandon de la possibilité d'avoir et des actions et des formulaires CVT dont l'URL soit indifféremment au niveau de la racine ou au niveau de {{{ecrire}}}: il ne faut pas obscuricr et ralentir l'accès aux scripts de {{{ecrire/}}}. * le traitement de la variable {{{redirect}}} dans la requête HTTP est modifié pour tenir compte des incohérences de PHP signalé dans #1510: * si la requête est en GET, cette variable a dû être encodée par {{{rawurlencode}}} * si la requête est en POST, elle ne doit pas avoir été encodée. Ce traitement est assuré par {{{generer_action_auteur}}} et ses fonctions annes, les extensions de SPIP utilisant cette fonction de manière standard ne seront pas affectées par ce changement interne. - vérification de tous les cas d'utilisation de cette variable de redirection, en particulier pour éliminer la production d'URL absolue dans le cas GET, le mod_security d'APACHE faisant de la parano là-dessus. En particulier, la solution de #1510 a imposé d'expliciter le script de retour des bouton de contrôle de forum, le double retour s'effectue à l'endroit attendu de {{{articles_forum}}}, ce qui est le cas aussi de {{{controle_forum}}} à présent, même en utilisation AJAX.
15 years ago
$r = rawurlencode($redirect);
if ($mode===-1)
return array('action'=>$action,'arg'=>$arg,'hash'=>$hash);
else
return generer_url_action($action, "arg=$arg&hash=$hash" . (!$r ? '' : "&redirect=$r"), $mode, $public);
}
// mode formulaire
$hash = calculer_action_auteur("$action-$arg");
$att .= " style='margin: 0px; border: 0px'";
Résolution de #1510, cette double redirection d'action conduisant à plusieurs changements: * réintégration dans le script {{{../public.php}}} de tous les cas ne suivant pas le déroulement complet d'utilisation d'un squelette (action, CVT) afin de migrer tous les appels à {{{exit}}} de {{{public/assembler}}} dans le script initial (il en reste un, dans la fonction repérant un violation de sécurité CVT ça peut se justifier). * abandon de la possibilité d'avoir et des actions et des formulaires CVT dont l'URL soit indifféremment au niveau de la racine ou au niveau de {{{ecrire}}}: il ne faut pas obscuricr et ralentir l'accès aux scripts de {{{ecrire/}}}. * le traitement de la variable {{{redirect}}} dans la requête HTTP est modifié pour tenir compte des incohérences de PHP signalé dans #1510: * si la requête est en GET, cette variable a dû être encodée par {{{rawurlencode}}} * si la requête est en POST, elle ne doit pas avoir été encodée. Ce traitement est assuré par {{{generer_action_auteur}}} et ses fonctions annes, les extensions de SPIP utilisant cette fonction de manière standard ne seront pas affectées par ce changement interne. - vérification de tous les cas d'utilisation de cette variable de redirection, en particulier pour éliminer la production d'URL absolue dans le cas GET, le mod_security d'APACHE faisant de la parano là-dessus. En particulier, la solution de #1510 a imposé d'expliciter le script de retour des bouton de contrôle de forum, le double retour s'effectue à l'endroit attendu de {{{articles_forum}}}, ce qui est le cas aussi de {{{controle_forum}}} à présent, même en utilisation AJAX.
15 years ago
if ($redirect)
$redirect = "\n\t\t<input name='redirect' type='hidden' value='". str_replace("'", '&#39;', $redirect) ."' />";
$mode .= $redirect . "
<input name='hash' type='hidden' value='$hash' />
<input name='arg' type='hidden' value='$arg' />";
return generer_form_action($action, $mode, $att, $public);
}
/**
* Caracteriser un auteur : l'auteur loge si $id_auteur=null
*
* http://doc.spip.org/@caracteriser_auteur
*
* @param int|null $id_auteur
* @return array
*/
function caracteriser_auteur($id_auteur=null) {
static $caracterisation = array();
if (is_null($id_auteur) AND !isset($GLOBALS['visiteur_session']['id_auteur'])) {
// si l'auteur courant n'est pas connu alors qu'il peut demander une action
// c'est une connexion par php_auth ou 1 instal, on se rabat sur le cookie.
// S'il n'avait pas le droit de realiser cette action, le hash sera faux.
if (isset($_COOKIE['spip_session'])
AND (preg_match('/^(\d+)/',$_COOKIE['spip_session'],$r))) {
return array($r[1], '');
// Necessaire aux forums anonymes.
// Pour le reste, ca echouera.
} else return array('0','');
}
// Eviter l'acces SQL si le pass est connu de PHP
if (is_null($id_auteur)){
$id_auteur = isset($GLOBALS['visiteur_session']['id_auteur'])?$GLOBALS['visiteur_session']['id_auteur']:0;
if (isset($GLOBALS['visiteur_session']['pass']) AND $GLOBALS['visiteur_session']['pass'])
return $caracterisation[$id_auteur] = array($id_auteur, $GLOBALS['visiteur_session']['pass']);
}
if (isset($caracterisation[$id_auteur])) return $caracterisation[$id_auteur];
if ($id_auteur) {
include_spip('base/abstract_sql');
$t = sql_fetsel("id_auteur, pass", "spip_auteurs", "id_auteur=$id_auteur");
if ($t)
return $caracterisation[$id_auteur] = array($t['id_auteur'], $t['pass']);
Pour eviter aux scripts Ajax de charger systématiquement les 130Ko totalisés par inc/minipres.php inc/texte.php inc/filtres.php et inc/charsets.php (et pour faciliter la lecture de ecrire/index.php aux nouveaux venus), cette suite d'inclusions ne sera bientot plus opérées par ecrire/index;php. Cette opération devait transparente pour le noyau, mais pourra etre perceptible pour les extensions de SPIP définissant ou complétant l'espace privé, notamment en créant des fichiers dans un répertoire exec/. Pour se préparer à ce changement, ces extensions ont deux possibilités: - la plus simple: rajouter dans leurs fichiers le {{{include_spip('inc/minipres/')}}} qui sera bientot retiré de ecrire/index.php - la plus pertinente: tester chacun de ces fichiers pour regarder s'ils ont besoin ou non de ces 130Ko. Pour ce faire on peut utiliser le shell-script suivant, où la variable {{{session}}} doit etre affectée à une session valide sur votre machine: #!/bin/sh session="require('../tmp/sessions/521_0a154a3fdb1dfa9443d8cec28e7c5743.php');" for i in ??*.php do z=../_$i.php sed "s,<\?php,<\?php require 'inc_version.php';spip_connect();include_spip('inc/sessions');$session," $i > $z f=$(basename $i .php) echo "<?php exec_${f}_dist(); ?>" >> $z echo ">>>>>>>>>>>>>$i" php -q $z |grep Fatal rm $z done Il faut aussi executer ce script avec {{{session=''}}} pour bien faire. Les messages de fonctions indéfinies qui pourraient arriver pendant ces exécutions signalent qu'une au moins des 4 inclusions éliminées est indispensable au script considéré, il faut alors l'ajouter à l'endroit approprié. Le présent dépot ajoute les inclusions repérées par ce shell-script. Elle sont donc superflues jusqu'au remplacement de inc/minipres par inc/lang dans index.php.
16 years ago
include_spip('inc/minipres');
echo minipres();
exit;
}
// Visiteur anonyme, pour ls forums par exemple
else {
return array('0','');
}
}
/**
* Calcule une cle securisee pour une action et un auteur donnes
* utilisee pour generer des urls personelles pour executer une action qui modifie la base
* et verifier la legitimite de l'appel a l'action
*
* http://doc.spip.org/@_action_auteur
*
* @param string $action
* @param int $id_auteur
* @param string $pass
* @param string $alea
* @return string
*/
function _action_auteur($action, $id_auteur, $pass, $alea) {
static $sha = array();
if (!isset($sha[$id_auteur.$pass.$alea])){
if (!isset($GLOBALS['meta'][$alea]) AND _request('exec')!=='install') {
include_spip('base/abstract_sql');
$GLOBALS['meta'][$alea] = sql_getfetsel('valeur', 'spip_meta', "nom=" . sql_quote($alea));
if (!($GLOBALS['meta'][$alea])) {
include_spip('inc/minipres');
echo minipres();
spip_log("$alea indisponible");
exit;
}
}
include_spip('auth/sha256.inc');
$sha[$id_auteur.$pass.$alea] = _nano_sha256($id_auteur.$pass.@$GLOBALS['meta'][$alea]);
}
if (function_exists('sha1'))
return sha1($action.$sha[$id_auteur.$pass.$alea]);
else
return md5($action.$sha[$id_auteur.$pass.$alea]);
}
/**
* Calculer le hash qui signe une action pour un auteur
* http://doc.spip.org/@calculer_action_auteur
*
* @param string $action
* @param int|null $id_auteur
* @return string
*/
function calculer_action_auteur($action, $id_auteur=null) {
list($id_auteur, $pass) = caracteriser_auteur($id_auteur);
return _action_auteur($action, $id_auteur, $pass, 'alea_ephemere');
}
/**
* Verifier le hash de signature d'une action
* toujours exclusivement pour l'auteur en cours
* http://doc.spip.org/@verifier_action_auteur
*
* @param $action
* @param $hash
* @return bool
*/
function verifier_action_auteur($action, $hash) {
list($id_auteur, $pass) = caracteriser_auteur();
if ($hash == _action_auteur($action, $id_auteur, $pass, 'alea_ephemere'))
return true;
if ($hash == _action_auteur($action, $id_auteur, $pass, 'alea_ephemere_ancien'))
return true;
return false;
}
//
// Des fonctions independantes du visiteur, qui permettent de controler
// par exemple que l'URL d'un document a la bonne cle de lecture
//
/**
* Renvoyer le secret du site, et le generer si il n'existe pas encore
* Le secret du site doit rester aussi secret que possible, et est eternel
* On ne doit pas l'exporter
*
* http://doc.spip.org/@secret_du_site
*
* @return string
*/
function secret_du_site() {
if (!isset($GLOBALS['meta']['secret_du_site'])){
include_spip('base/abstract_sql');
$GLOBALS['meta']['secret_du_site'] = sql_getfetsel('valeur', 'spip_meta', "nom='secret_du_site'");
}
if (!isset($GLOBALS['meta']['secret_du_site'])
OR (strlen($GLOBALS['meta']['secret_du_site'])<64)) {
include_spip('inc/acces');
include_spip('auth/sha256.inc');
ecrire_meta('secret_du_site', _nano_sha256($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SERVER_SIGNATURE"] . creer_uniqid()), 'non');
15 years ago
lire_metas(); // au cas ou ecrire_meta() ne fonctionne pas
}
return $GLOBALS['meta']['secret_du_site'];
}
/**
* Calculer une signature valable pour une action et pour le site
* http://doc.spip.org/@calculer_cle_action
*
* @param string $action
* @return string
*/
function calculer_cle_action($action) {
if (function_exists('sha1'))
return sha1($action . secret_du_site());
else
return md5($action . secret_du_site());
}
/**
* Verifier la cle de signature d'une action valable pour le site
* http://doc.spip.org/@verifier_cle_action
*
* @param string $action
* @param string $cle
* @return bool
*/
function verifier_cle_action($action, $cle) {
return ($cle == calculer_cle_action($action));
}
?>