diff --git a/conf/ecran_securite.php b/conf/ecran_securite.php new file mode 100644 index 0000000..53581fc --- /dev/null +++ b/conf/ecran_securite.php @@ -0,0 +1,758 @@ + $val) { + if ( + $_GET[$var] and strncmp($var, "id_", 3) == 0 + and !in_array($var, $_exceptions) + ) { + $_GET[$var] = is_array($_GET[$var]) ? @array_map('intval', $_GET[$var]) : intval($_GET[$var]); + } +} +foreach ($_POST as $var => $val) { + if ( + $_POST[$var] and strncmp($var, "id_", 3) == 0 + and !in_array($var, $_exceptions) + ) { + $_POST[$var] = is_array($_POST[$var]) ? @array_map('intval', $_POST[$var]) : intval($_POST[$var]); + } +} +foreach ($GLOBALS as $var => $val) { + if ( + $GLOBALS[$var] and strncmp($var, "id_", 3) == 0 + and !in_array($var, $_exceptions) + ) { + $GLOBALS[$var] = is_array($GLOBALS[$var]) ? @array_map('intval', $GLOBALS[$var]) : intval($GLOBALS[$var]); + } +} + +/* + * Interdit la variable $cjpeg_command, qui était utilisée sans + * précaution dans certaines versions de dev (1.8b2 -> 1.8b5) + */ +$cjpeg_command = ''; + +/* + * Contrôle de quelques variables (XSS) + */ +foreach (array('lang', 'var_recherche', 'aide', 'var_lang_r', 'lang_r', 'var_ajax_ancre', 'nom_fichier') as $var) { + if (isset($_GET[$var])) { + $_REQUEST[$var] = $GLOBALS[$var] = $_GET[$var] = preg_replace(',[^\w\,/#&;-]+,', ' ', (string)$_GET[$var]); + } + if (isset($_POST[$var])) { + $_REQUEST[$var] = $GLOBALS[$var] = $_POST[$var] = preg_replace(',[^\w\,/#&;-]+,', ' ', (string)$_POST[$var]); + } +} + +/* + * Filtre l'accès à spip_acces_doc (injection SQL en 1.8.2x) + */ +if (isset($_SERVER['REQUEST_URI'])) { + if (preg_match(',^(.*/)?spip_acces_doc\.,', (string)$_SERVER['REQUEST_URI'])) { + $file = addslashes((string)$_GET['file']); + } +} + +/* + * Pas d'inscription abusive + */ +if ( + isset($_REQUEST['mode']) and isset($_REQUEST['page']) + and !in_array($_REQUEST['mode'], array("6forum", "1comite")) + and $_REQUEST['page'] == "identifiants" +) { + $ecran_securite_raison = "identifiants"; +} + +/* + * Agenda joue à l'injection php + */ +if ( + isset($_REQUEST['partie_cal']) + and $_REQUEST['partie_cal'] !== htmlentities((string)$_REQUEST['partie_cal']) +) { + $ecran_securite_raison = "partie_cal"; +} +if ( + isset($_REQUEST['echelle']) + and $_REQUEST['echelle'] !== htmlentities((string)$_REQUEST['echelle']) +) { + $ecran_securite_raison = "echelle"; +} + +/* + * Espace privé + */ +if ( + isset($_REQUEST['exec']) + and !preg_match(',^[\w-]+$,', (string)$_REQUEST['exec']) +) { + $ecran_securite_raison = "exec"; +} +if ( + isset($_REQUEST['cherche_auteur']) + and preg_match(',[<],', (string)$_REQUEST['cherche_auteur']) +) { + $ecran_securite_raison = "cherche_auteur"; +} +if ( + isset($_REQUEST['exec']) + and $_REQUEST['exec'] == 'auteurs' + and isset($_REQUEST['recherche']) + and preg_match(',[<],', (string)$_REQUEST['recherche']) +) { + $ecran_securite_raison = "recherche"; +} +if ( + isset($_REQUEST['exec']) + and $_REQUEST['exec'] == 'info_plugin' + and isset($_REQUEST['plugin']) + and preg_match(',[<],', (string)$_REQUEST['plugin']) +) { + $ecran_securite_raison = "plugin"; +} +if ( + isset($_REQUEST['exec']) + and $_REQUEST['exec'] == 'puce_statut' + and isset($_REQUEST['id']) + and !intval($_REQUEST['id']) +) { + $ecran_securite_raison = "puce_statut"; +} +if ( + isset($_REQUEST['action']) + and $_REQUEST['action'] == 'configurer' +) { + if ( + @file_exists('inc_version.php') + or @file_exists('ecrire/inc_version.php') + ) { + function action_configurer() { + include_spip('inc/autoriser'); + if (!autoriser('configurer', _request('configuration'))) { + include_spip('inc/minipres'); + echo minipres(_T('info_acces_interdit')); + exit; + } + require _DIR_RESTREINT . 'action/configurer.php'; + action_configurer_dist(); + } + } +} +if ( + isset($_REQUEST['action']) + and $_REQUEST['action'] == 'ordonner_liens_documents' + and isset($_REQUEST['ordre']) + and is_string($_REQUEST['ordre']) +) { + $ecran_securite_raison = "ordre a la chaine"; +} + + +/* + * Bloque les requêtes contenant %00 (manipulation d'include) + */ +if (strpos( + (function_exists('get_magic_quotes_gpc') and @get_magic_quotes_gpc()) + ? stripslashes(serialize($_REQUEST)) + : serialize($_REQUEST), + chr(0) +) !== false) { + $ecran_securite_raison = "%00"; +} + +/* + * Bloque les requêtes fond=formulaire_ + */ +if ( + isset($_REQUEST['fond']) + and preg_match(',^formulaire_,i', $_REQUEST['fond']) +) { + $ecran_securite_raison = "fond=formulaire_"; +} + +/* + * Bloque les requêtes du type ?GLOBALS[type_urls]=toto (bug vieux php) + */ +if (isset($_REQUEST['GLOBALS'])) { + $ecran_securite_raison = "GLOBALS[GLOBALS]"; +} + +/* + * Bloque les requêtes des bots sur: + * les agenda + * les paginations entremélées + */ +if (_IS_BOT) { + if ( + (isset($_REQUEST['echelle']) and isset($_REQUEST['partie_cal']) and isset($_REQUEST['type'])) + or (strpos((string)$_SERVER['REQUEST_URI'], 'debut_') and preg_match(',[?&]debut_.*&debut_,', (string)$_SERVER['REQUEST_URI'])) + or (isset($_REQUEST['calendrier_annee']) and strpos((string)$_SERVER['REQUEST_URI'], 'debut_')) + or (isset($_REQUEST['calendrier_annee']) and preg_match(',[?&]calendrier_annee=.*&calendrier_annee=,', (string)$_SERVER['REQUEST_URI'])) + ) { + $ecran_securite_raison = "robot agenda/double pagination"; + } +} + +/* + * Bloque une vieille page de tests de CFG (<1.11) + * Bloque un XSS sur une page inexistante + */ +if (isset($_REQUEST['page'])) { + if ($_REQUEST['page'] == 'test_cfg') { + $ecran_securite_raison = "test_cfg"; + } + if ($_REQUEST['page'] !== htmlspecialchars((string)$_REQUEST['page'])) { + $ecran_securite_raison = "xsspage"; + } + if ( + $_REQUEST['page'] == '404' + and isset($_REQUEST['erreur']) + ) { + $ecran_securite_raison = "xss404"; + } +} + +/* + * XSS par array + */ +foreach (array('var_login') as $var) { + if (isset($_REQUEST[$var]) and is_array($_REQUEST[$var])) { + $ecran_securite_raison = "xss " . $var; + } +} + +/* + * Parade antivirale contre un cheval de troie + */ +if (!function_exists('tmp_lkojfghx')) { + function tmp_lkojfghx() {} + function tmp_lkojfghx2($a = 0, $b = 0, $c = 0, $d = 0) { + // si jamais on est arrivé ici sur une erreur php + // et qu'un autre gestionnaire d'erreur est défini, l'appeller + if ($b && $GLOBALS['tmp_xhgfjokl']) { + call_user_func($GLOBALS['tmp_xhgfjokl'], $a, $b, $c, $d); + } + } +} +if (isset($_POST['tmp_lkojfghx3'])) { + $ecran_securite_raison = "gumblar"; +} + +/* + * Outils XML mal sécurisés < 2.0.9 + */ +if (isset($_REQUEST['transformer_xml'])) { + $ecran_securite_raison = "transformer_xml"; +} + +/* + * Outils XML mal sécurisés again + */ +if (isset($_REQUEST['var_url']) and $_REQUEST['var_url'] and isset($_REQUEST['exec']) and $_REQUEST['exec'] == 'valider_xml') { + $url = trim($_REQUEST['var_url']); + if ( + strncmp($url, '/', 1) == 0 + or (($p = strpos($url, '..')) !== false and strpos($url, '..', $p + 3) !== false) + or (($p = strpos($url, '..')) !== false and strpos($url, 'IMG', $p + 3) !== false) + or (strpos($url, '://') !== false or strpos($url, ':\\') !== false) + ) { + $ecran_securite_raison = 'URL interdite pour var_url'; + } +} + +/* + * Sauvegarde mal securisée < 2.0.9 + */ +if ( + isset($_REQUEST['nom_sauvegarde']) + and strstr((string)$_REQUEST['nom_sauvegarde'], '/') +) { + $ecran_securite_raison = 'nom_sauvegarde manipulee'; +} +if ( + isset($_REQUEST['znom_sauvegarde']) + and strstr((string)$_REQUEST['znom_sauvegarde'], '/') +) { + $ecran_securite_raison = 'znom_sauvegarde manipulee'; +} + + +/* + * op permet des inclusions arbitraires ; + * on vérifie 'page' pour ne pas bloquer ... drupal + */ +if ( + isset($_REQUEST['op']) and isset($_REQUEST['page']) + and $_REQUEST['op'] !== preg_replace('/[^\\-\w]/', '', $_REQUEST['op']) +) { + $ecran_securite_raison = 'op'; +} + +/* + * Forms & Table ne se méfiait pas assez des uploads de fichiers + */ +if (count($_FILES)) { + foreach ($_FILES as $k => $v) { + if ( + preg_match(',^fichier_\d+$,', $k) + and preg_match(',\.php,i', $v['name']) + ) { + unset($_FILES[$k]); + } + } +} +/* + * et Contact trop laxiste avec une variable externe + * on bloque pas le post pour eviter de perdre des donnees mais on unset la variable et c'est tout + */ +if (isset($_REQUEST['pj_enregistrees_nom']) and $_REQUEST['pj_enregistrees_nom']) { + unset($_REQUEST['pj_enregistrees_nom']); + unset($_GET['pj_enregistrees_nom']); + unset($_POST['pj_enregistrees_nom']); +} + +/* + * reinstall=oui un peu trop permissif + */ +if ( + isset($_REQUEST['reinstall']) + and $_REQUEST['reinstall'] == 'oui' +) { + $ecran_securite_raison = 'reinstall=oui'; +} + +/* + * Pas d'action pendant l'install + */ +if (isset($_REQUEST['exec']) and $_REQUEST['exec'] === 'install' and isset($_REQUEST['action'])) { + $ecran_securite_raison = 'install&action impossibles'; +} + +/* + * Échappement xss referer + */ +if (isset($_SERVER['HTTP_REFERER'])) { + $_SERVER['HTTP_REFERER'] = strtr($_SERVER['HTTP_REFERER'], '<>"\'', '[]##'); +} + + +/* + * Echappement HTTP_X_FORWARDED_HOST + */ +if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { + $_SERVER['HTTP_X_FORWARDED_HOST'] = strtr($_SERVER['HTTP_X_FORWARDED_HOST'], "<>?\"\{\}\$'` \r\n", '____________'); +} + + +/* + * Pas d'erreur dans l'erreur + */ +if (isset($_REQUEST['var_erreur']) and isset($_REQUEST['page']) and $_REQUEST['page'] === 'login') { + if (strlen($_REQUEST['var_erreur']) !== strcspn($_REQUEST['var_erreur'], '<>')) { + $ecran_securite_raison = 'var_erreur incorrecte'; + } +} + + +/* + * Réinjection des clés en html dans l'admin r19561 + */ +if ( + (isset($_SERVER['REQUEST_URI']) and strpos($_SERVER['REQUEST_URI'], "ecrire/") !== false) + or isset($_REQUEST['var_memotri']) +) { + $zzzz = implode("", array_keys($_REQUEST)); + if (strlen($zzzz) != strcspn($zzzz, '<>"\'')) { + $ecran_securite_raison = 'Cle incorrecte en $_REQUEST'; + } +} + +/* + * Injection par connect + */ +if ( + isset($_REQUEST['connect']) + // cas qui permettent de sortir d'un commentaire PHP + and ( + strpos($_REQUEST['connect'], "?") !== false + or strpos($_REQUEST['connect'], "<") !== false + or strpos($_REQUEST['connect'], ">") !== false + or strpos($_REQUEST['connect'], "\n") !== false + or strpos($_REQUEST['connect'], "\r") !== false + ) +) { + $ecran_securite_raison = "malformed connect argument"; +} + + +/* + * _oups donc + */ +if ( + isset($_REQUEST['_oups']) + and base64_decode($_REQUEST['_oups'], true) === false) { + $ecran_securite_raison = "malformed _oups argument"; +} + +if ( + isset($_REQUEST['formulaire_action_args']) || isset($_REQUEST['var_login']) +) { + foreach ($_REQUEST as $k => $v) { + if (is_string($v) + and strpbrk($v, "&\"'<>") !== false + and preg_match(',^[abis]:\d+[:;],', $v) + and __ecran_test_if_serialized($v) + ) { + $_REQUEST[$k] = htmlspecialchars($v, ENT_QUOTES); + if (isset($_POST[$k])) $_POST[$k] = $_REQUEST[$k]; + if (isset($_GET[$k])) $_GET[$k] = $_REQUEST[$k]; + } + } +} +/** + * Version simplifiée de https://developer.wordpress.org/reference/functions/is_serialized/ + */ +function __ecran_test_if_serialized($data) { + $data = trim($data); + if ('N;' === $data) {return true;} + if (strlen($data) < 4) {return false;} + if (':' !== $data[1]) {return false;} + $semicolon = strpos($data, ';'); + $brace = strpos($data, '}'); + // Either ; or } must exist. + if (false === $semicolon && false === $brace) {return false;} + // But neither must be in the first X characters. + if (false !== $semicolon && $semicolon < 3) {return false;} + if (false !== $brace && $brace < 4) {return false;} + $token = $data[0]; + if (in_array($token, array('s', 'S', 'a', 'O', 'C', 'o', 'E'))) { + if (in_array($token, array('s', 'S')) and false === strpos($data, '"')) {return false;} + return (bool)preg_match("/^{$token}:[0-9]+:/s", $data); + } elseif (in_array($token, array('b', 'i', 'd'))) { + return (bool)preg_match("/^{$token}:[0-9.E+-]+;/", $data); + } + return false; +} + + +/* + * S'il y a une raison de mourir, mourons + */ +if (isset($ecran_securite_raison)) { + header("HTTP/1.0 403 Forbidden"); + header("Expires: Wed, 11 Jan 1984 05:00:00 GMT"); + header("Cache-Control: no-cache, must-revalidate"); + header("Pragma: no-cache"); + header("Content-Type: text/html"); + header("Connection: close"); + die("Error 403: Forbidden

Error 403

You are not authorized to view this page ($ecran_securite_raison)

"); +} + +/* + * Un filtre filtrer_entites securise + */ +if (!function_exists('filtre_filtrer_entites_dist')) { + function filtre_filtrer_entites_dist($t) { + include_spip('inc/texte'); + return interdire_scripts(filtrer_entites($t)); + } +} + + +/* + * Fin sécurité + */ + + + +/* + * Bloque les bots quand le load déborde + */ +if (!defined('_ECRAN_SECURITE_LOAD')) { + define('_ECRAN_SECURITE_LOAD', 4); +} + +if ( + defined('_ECRAN_SECURITE_LOAD') + and _ECRAN_SECURITE_LOAD > 0 + and _IS_BOT + and !_IS_BOT_FRIEND + and $_SERVER['REQUEST_METHOD'] === 'GET' + and ( + (function_exists('sys_getloadavg') + and $load = sys_getloadavg() + and is_array($load) + and $load = array_shift($load)) + or + (@is_readable('/proc/loadavg') + and $load = file_get_contents('/proc/loadavg') + and $load = floatval($load)) + ) + and $load > _ECRAN_SECURITE_LOAD // eviter l'evaluation suivante si de toute facon le load est inferieur a la limite + and rand(0, (int) ($load * $load)) > _ECRAN_SECURITE_LOAD * _ECRAN_SECURITE_LOAD +) { + //https://webmasters.stackexchange.com/questions/65674/should-i-return-a-429-or-503-status-code-to-a-bot + header("HTTP/1.0 429 Too Many Requests"); + header("Retry-After: 300"); + header("Expires: Wed, 11 Jan 1984 05:00:00 GMT"); + header("Cache-Control: no-cache, must-revalidate"); + header("Pragma: no-cache"); + header("Content-Type: text/html"); + header("Connection: close"); + die("Status 429: Too Many Requests

Status 429

Too Many Requests (try again soon)

"); +} diff --git a/scripts/install b/scripts/install index 17705a0..b90394c 100644 --- a/scripts/install +++ b/scripts/install @@ -162,6 +162,9 @@ ynh_script_progression --message="Adding a configuration file..." #ynh_replace_string "'','utf8');" "'ldap.php','utf8');" $final_path/config/connect.php cp ../conf/mes_options.php $final_path/config/mes_options.php +# Add security fix https://www.spip.net/en_article4201.html +cp ../conf/ecran_securite.php $final_path/config/ecran_securite.php + #================================================= # STORE THE CONFIG FILE CHECKSUM #=================================================