Newer
Older
<?php
/*
* ecran_securite.php
* ------------------
*/
define('_ECRAN_SECURITE', '1.5.3'); // 2023-05-31
* Documentation : https://www.spip.net/fr_article4200.html
* Test utilisateur
marcimat
a validé
if (isset($_GET['test_ecran_securite'])) {
$ecran_securite_raison = 'test ' . _ECRAN_SECURITE;
}
if (file_exists($f = __DIR__ . DIRECTORY_SEPARATOR . 'ecran_securite_options.php')) {
include ($f);
}
cerdic
a validé
/*
* Monitoring
* var_isbot=0 peut etre utilise par un bot de monitoring pour surveiller la disponibilite d'un site vu par les users
* var_isbot=1 peut etre utilise pour monitorer la disponibilite pour les bots (sujets a 503 de delestage si
* le load depasse ECRAN_SECURITE_LOAD)
*/
marcimat
a validé
if (!defined('_IS_BOT') and isset($_GET['var_isbot'])) {
define('_IS_BOT', $_GET['var_isbot'] ? true : false);
}
cerdic
a validé
* Détecteur de robot d'indexation
marcimat
a validé
if (!defined('_IS_BOT')) {
define(
'_IS_BOT',
marcimat
a validé
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
and preg_match(
','
. implode('|', array(
// mots generiques
'bot',
'slurp',
'crawler',
'crwlr',
'java',
'monitoring',
'spider',
'webvac',
'yandex',
'MSIE 6\.0', // botnet 99,9% du temps
// UA plus cibles
'200please',
'80legs',
'a6-indexer',
'aboundex',
'accoona',
'acrylicapps',
'addthis',
'adressendeutschland',
'alexa',
'altavista',
'analyticsseo',
'antennapod',
'arachnys',
'archive',
'argclrint',
'aspseek',
'baidu',
'begunadvertising',
'bing',
'bloglines',
'buck',
'browsershots',
'bubing',
'butterfly',
'changedetection',
'charlotte',
'chilkat',
'china',
'coccoc',
'crowsnest',
'dataminr',
'daumoa',
'dlvr\.it',
'dlweb',
'drupal',
'ec2linkfinder',
'eset\.com',
'estyle',
'exalead',
'ezooms',
'facebookexternalhit',
'facebookplatform',
'fairshare',
'feedfetcher',
'feedfetcher-google',
'feedly',
'fetch',
'flipboardproxy',
'genieo',
'google',
'go-http-client',
'grapeshot',
'hatena-useragent',
'head',
'hosttracker',
'hubspot',
'ia_archiver',
'ichiro',
'iltrovatore-setaccio',
'immediatenet',
'ina',
'inoreader',
'infegyatlas',
'infohelfer',
'instapaper',
'jabse',
'james',
'jersey',
'kumkie',
'linkdex',
'linkfluence',
'linkwalker',
'litefinder',
'loadimpactpageanalyzer',
'ltx71',
'luminate',
'lycos',
'lycosa',
'mediapartners-google',
'msai',
'myapp',
'nativehost',
'najdi',
'netcraftsurveyagent',
'netestate',
'netseer',
'netnewswire',
'newspaper',
'newsblur',
'nuhk',
'nuzzel',
'okhttp',
'otmedia',
'owlin',
'owncloud',
'panscient',
'paper\.li',
'parsijoo',
'protopage',
'plukkie',
'proximic',
'pubsub',
'python',
'qirina',
'qoshe',
'qualidator',
'qwantify',
'rambler',
'readability',
'ruby',
'sbsearch',
'scoop\.it',
'scooter',
'scoutjet',
'scrapy',
'scrubby',
'scrubbybloglines',
'shareaholic',
'shopwiki',
'simplepie',
'sistrix',
'sitechecker',
'siteexplorer',
'snapshot',
'sogou',
'special_archiver',
'speedy',
'spinn3r',
'spreadtrum',
'steeler',
'subscriber',
'suma',
'superdownloads',
'svenska-webbsido',
'teoma',
'the knowledge AI',
'thumbshots',
'tineye',
'traackr',
'trendiction',
'trendsmap',
'tweetedtimes',
'tweetmeme',
'universalfeedparser',
'uaslinkchecker',
'undrip',
'unwindfetchor',
'upday',
'vedma',
'vkshare',
'vm',
'wch',
'webalta',
'webcookies',
'webparser',
'webthumbnail',
'wesee',
'wise-guys',
'woko',
'wordpress',
'wotbox',
'y!j-bri',
'y!j-bro',
'y!j-brw',
'y!j-bsc',
'yahoo',
'yahoo!',
'yahooysmcm',
'ymobactus',
'yats',
'yeti',
'zeerch'
)) . ',i',
(string)$_SERVER['HTTP_USER_AGENT']
)
}
marcimat
a validé
if (!defined('_IS_BOT_FRIEND')) {
define(
'_IS_BOT_FRIEND',
isset($_SERVER['HTTP_USER_AGENT'])
marcimat
a validé
and preg_match(
',' . implode('|', array(
'facebookexternalhit',
cerdic
a validé
'twitterbot',
marcimat
a validé
'flipboardproxy',
'wordpress'
)) . ',i',
(string)$_SERVER['HTTP_USER_AGENT']
)
);
}
/*
* Interdit de passer une variable id_article (ou id_xxx) qui ne
* soit pas numérique (ce qui bloque l'exploitation de divers trous
* de sécurité, dont celui de toutes les versions < 1.8.2f)
* (sauf pour id_table, qui n'est pas numérique jusqu'à [5743])
* (id_base est une variable de la config des widgets de WordPress)
marcimat
a validé
$_exceptions = array('id_table', 'id_base', 'id_parent', 'id_article_pdf');
foreach ($_GET as $var => $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)
marcimat
a validé
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]);
marcimat
a validé
}
if (isset($_POST[$var])) {
$_REQUEST[$var] = $GLOBALS[$var] = $_POST[$var] = preg_replace(',[^\w\,/#&;-]+,', ' ', (string)$_POST[$var]);
marcimat
a validé
}
/*
* 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
*/
marcimat
a validé
if (
isset($_REQUEST['mode']) and isset($_REQUEST['page'])
and !in_array($_REQUEST['mode'], array("6forum", "1comite"))
and $_REQUEST['page'] == "identifiants"
) {
$ecran_securite_raison = "identifiants";
marcimat
a validé
}
* Agenda joue à l'injection php
marcimat
a validé
if (
isset($_REQUEST['partie_cal'])
and $_REQUEST['partie_cal'] !== htmlentities((string)$_REQUEST['partie_cal'])
) {
marcimat
a validé
}
if (
isset($_REQUEST['echelle'])
and $_REQUEST['echelle'] !== htmlentities((string)$_REQUEST['echelle'])
) {
marcimat
a validé
}
marcimat
a validé
if (
isset($_REQUEST['exec'])
and !preg_match(',^[\w-]+$,', (string)$_REQUEST['exec'])
) {
marcimat
a validé
}
if (
isset($_REQUEST['cherche_auteur'])
and preg_match(',[<],', (string)$_REQUEST['cherche_auteur'])
) {
marcimat
a validé
}
if (
isset($_REQUEST['exec'])
and $_REQUEST['exec'] == 'auteurs'
and isset($_REQUEST['recherche'])
marcimat
a validé
and preg_match(',[<],', (string)$_REQUEST['recherche'])
) {
$ecran_securite_raison = "recherche";
marcimat
a validé
}
if (
isset($_REQUEST['exec'])
and $_REQUEST['exec'] == 'info_plugin'
and isset($_REQUEST['plugin'])
marcimat
a validé
and preg_match(',[<],', (string)$_REQUEST['plugin'])
) {
marcimat
a validé
}
if (
isset($_REQUEST['exec'])
and $_REQUEST['exec'] == 'puce_statut'
and isset($_REQUEST['id'])
and !intval($_REQUEST['id'])
) {
marcimat
a validé
}
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');
marcimat
a validé
if (!autoriser('configurer', _request('configuration'))) {
include_spip('inc/minipres');
echo minipres(_T('info_acces_interdit'));
exit;
}
marcimat
a validé
require _DIR_RESTREINT . 'action/configurer.php';
marcimat
a validé
if (
isset($_REQUEST['action'])
and $_REQUEST['action'] == 'ordonner_liens_documents'
and isset($_REQUEST['ordre'])
and is_string($_REQUEST['ordre'])
) {
/*
* Bloque les requêtes contenant %00 (manipulation d'include)
marcimat
a validé
(function_exists('get_magic_quotes_gpc') and @get_magic_quotes_gpc())
? stripslashes(serialize($_REQUEST))
: serialize($_REQUEST),
marcimat
a validé
) !== false) {
marcimat
a validé
}
/*
* Bloque les requêtes fond=formulaire_
marcimat
a validé
if (
isset($_REQUEST['fond'])
and preg_match(',^formulaire_,i', $_REQUEST['fond'])
) {
marcimat
a validé
}
/*
* Bloque les requêtes du type ?GLOBALS[type_urls]=toto (bug vieux php)
marcimat
a validé
if (isset($_REQUEST['GLOBALS'])) {
marcimat
a validé
}
/*
* Bloque les requêtes des bots sur:
* les agenda
* les paginations entremélées
marcimat
a validé
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']))
marcimat
a validé
) {
$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'])) {
marcimat
a validé
if ($_REQUEST['page'] == 'test_cfg') {
marcimat
a validé
}
if ($_REQUEST['page'] !== htmlspecialchars((string)$_REQUEST['page'])) {
marcimat
a validé
}
if (
$_REQUEST['page'] == '404'
and isset($_REQUEST['erreur'])
) {
marcimat
a validé
}
marcimat
a validé
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() {}
gilles.vincent
a validé
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
marcimat
a validé
if ($b && $GLOBALS['tmp_xhgfjokl']) {
call_user_func($GLOBALS['tmp_xhgfjokl'], $a, $b, $c, $d);
marcimat
a validé
}
marcimat
a validé
if (isset($_POST['tmp_lkojfghx3'])) {
marcimat
a validé
}
* Outils XML mal sécurisés < 2.0.9
marcimat
a validé
if (isset($_REQUEST['transformer_xml'])) {
marcimat
a validé
}
/*
* Outils XML mal sécurisés again
*/
marcimat
a validé
if (isset($_REQUEST['var_url']) and $_REQUEST['var_url'] and isset($_REQUEST['exec']) and $_REQUEST['exec'] == 'valider_xml') {
$url = trim($_REQUEST['var_url']);
marcimat
a validé
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
marcimat
a validé
if (
isset($_REQUEST['nom_sauvegarde'])
and strstr((string)$_REQUEST['nom_sauvegarde'], '/')
) {
marcimat
a validé
}
if (
isset($_REQUEST['znom_sauvegarde'])
and strstr((string)$_REQUEST['znom_sauvegarde'], '/')
) {
marcimat
a validé
}
/*
* op permet des inclusions arbitraires ;
* on vérifie 'page' pour ne pas bloquer ... drupal
marcimat
a validé
if (
isset($_REQUEST['op']) and isset($_REQUEST['page'])
and $_REQUEST['op'] !== preg_replace('/[^\\-\w]/', '', $_REQUEST['op'])
marcimat
a validé
) {
marcimat
a validé
}
/*
* Forms & Table ne se méfiait pas assez des uploads de fichiers
*/
marcimat
a validé
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
*/
marcimat
a validé
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
*/
marcimat
a validé
if (
isset($_REQUEST['reinstall'])
and $_REQUEST['reinstall'] == 'oui'
) {
$ecran_securite_raison = 'reinstall=oui';
marcimat
a validé
}
/*
* 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
*/
marcimat
a validé
if (isset($_SERVER['HTTP_REFERER'])) {
$_SERVER['HTTP_REFERER'] = strtr($_SERVER['HTTP_REFERER'], '<>"\'', '[]##');
marcimat
a validé
}
/*
* Echappement HTTP_X_FORWARDED_HOST
*/
marcimat
a validé
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$_SERVER['HTTP_X_FORWARDED_HOST'] = strtr($_SERVER['HTTP_X_FORWARDED_HOST'], "<>?\"\{\}\$'` \r\n", '____________');
marcimat
a validé
}
/*
* Pas d'erreur dans l'erreur
*/
if (isset($_REQUEST['var_erreur']) and isset($_REQUEST['page']) and $_REQUEST['page'] === 'login') {
marcimat
a validé
if (strlen($_REQUEST['var_erreur']) !== strcspn($_REQUEST['var_erreur'], '<>')) {
$ecran_securite_raison = 'var_erreur incorrecte';
marcimat
a validé
}
/*
* 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'])
marcimat
a validé
) {
$zzzz = implode("", array_keys($_REQUEST));
marcimat
a validé
if (strlen($zzzz) != strcspn($zzzz, '<>"\'')) {
marcimat
a validé
}
/*
* Injection par connect
*/
marcimat
a validé
if (
isset($_REQUEST['connect'])
// cas qui permettent de sortir d'un commentaire PHP
marcimat
a validé
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";
}
cerdic
a validé
if (
isset($_REQUEST['formulaire_action_args']) || isset($_REQUEST['var_login'])
cerdic
a validé
) {
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);
cerdic
a validé
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");
die("<html><title>Error 403: Forbidden</title><body><h1>Error 403</h1><p>You are not authorized to view this page ($ecran_securite_raison)</p></body></html>");
}
cerdic
a validé
/*
* 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));
}
}
* Bloque les bots quand le load déborde
marcimat
a validé
if (!defined('_ECRAN_SECURITE_LOAD')) {
marcimat
a validé
}
and _ECRAN_SECURITE_LOAD > 0
marcimat
a validé
and _IS_BOT
and !_IS_BOT_FRIEND
marcimat
a validé
and $_SERVER['REQUEST_METHOD'] === 'GET'
and (
(function_exists('sys_getloadavg')
marcimat
a validé
and $load = sys_getloadavg()
and is_array($load)
and $load = array_shift($load))
marcimat
a validé
or
(@is_readable('/proc/loadavg')
marcimat
a validé
and $load = file_get_contents('/proc/loadavg')
and $load = floatval($load))
marcimat
a validé
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");
die("<html><title>Status 429: Too Many Requests</title><body><h1>Status 429</h1><p>Too Many Requests (try again soon)</p></body></html>");