source: spip-zone/_core_/securite/ecran_securite.php

Last change on this file was 112421, checked in by root, 2 months ago

ajout de robots qui font des hits sur des pages html + finalement ne pas lister les lecteurs RSS et podcast ici. Il ne sont pas comptés dans les stats de spip par défaut, et on ne souhaite pas les bloquer en cas de load.

File size: 14.3 KB
Line 
1<?php
2
3/*
4 * ecran_securite.php
5 * ------------------
6 */
7
8define('_ECRAN_SECURITE', '1.3.8'); // 2018-10-31
9
10/*
11 * Documentation : http://www.spip.net/fr_article4200.html
12 */
13
14/*
15 * Test utilisateur
16 */
17if (isset($_GET['test_ecran_securite']))
18        $ecran_securite_raison = 'test '._ECRAN_SECURITE;
19
20/*
21 * Monitoring
22 * var_isbot=0 peut etre utilise par un bot de monitoring pour surveiller la disponibilite d'un site vu par les users
23 * var_isbot=1 peut etre utilise pour monitorer la disponibilite pour les bots (sujets a 503 de delestage si
24 * le load depasse ECRAN_SECURITE_LOAD)
25 */
26if (!defined('_IS_BOT') and isset($_GET['var_isbot'])){
27        define('_IS_BOT', $_GET['var_isbot'] ? true : false);
28}
29
30/*
31 * Détecteur de robot d'indexation
32 */
33if (!defined('_IS_BOT')){
34        define('_IS_BOT',
35                isset($_SERVER['HTTP_USER_AGENT'])
36                and preg_match(','
37                . implode ('|', array(
38                        // mots generiques
39                        'bot',
40                        'slurp',
41                        'crawler',
42                        'crwlr',
43                        'java',
44                        'monitoring',
45                        'spider',
46                        'webvac',
47                        'yandex',
48                        'MSIE 6\.0', // botnet 99,9% du temps
49                        // UA plus cibles
50                        '200please',
51                        '80legs',
52                        'a6-indexer',
53                        'aboundex',
54                        'accoona',
55                        'acrylicapps',
56                        'addthis',
57                        'adressendeutschland',
58                        'alexa',
59                        'altavista',
60                        'analyticsseo',
61                        'antennapod',
62                        'arachnys',
63                        'archive',
64                        'argclrint',
65                        'aspseek',
66                        'baidu',
67                        'begunadvertising',
68                        'bing',
69                        'bloglines',
70                        'buck',
71                        'browsershots',
72                        'bubing',
73                        'butterfly',
74                        'changedetection',
75                        'charlotte',
76                        'chilkat',
77                        'china',
78                        'coccoc',
79                        'crowsnest',
80                        'dataminr',
81                        'daumoa',
82                        'dlvr\.it',
83                        'dlweb',
84                        'drupal',
85                        'ec2linkfinder',
86                        'eset\.com',
87                        'estyle',
88                        'exalead',
89                        'ezooms',
90                        'facebookexternalhit',
91                        'facebookplatform',
92                        'fairshare',
93                        'feedfetcher',
94                        'feedfetcher-google',
95                        'feedly',
96                        'fetch',
97                        'flipboardproxy',
98                        'genieo',
99                        'google',
100                        'go-http-client',
101                        'grapeshot',
102                        'hatena-useragent',
103                        'head',
104                        'hosttracker',
105                        'hubspot',
106                        'ia_archiver',
107                        'ichiro',
108                        'iltrovatore-setaccio',
109                        'immediatenet',
110                        'ina',
111                        'inoreader',
112                        'infegyatlas',
113                        'infohelfer',
114                        'instapaper',
115                        'jabse',
116                        'james',
117                        'jersey',
118                        'kumkie',
119                        'linkdex',
120                        'linkfluence',
121                        'linkwalker',
122                        'litefinder',
123                        'loadimpactpageanalyzer',
124                        'ltx71',
125                        'luminate',
126                        'lycos',
127                        'lycosa',
128                        'mediapartners-google',
129                        'msai',
130                        'myapp',
131                        'nativehost',
132                        'najdi',
133                        'netcraftsurveyagent',
134                        'netestate',
135                        'netseer',
136                        'netnewswire',
137                        'newspaper',
138                        'newsblur',
139                        'nuhk',
140                        'nuzzel',
141                        'okhttp',
142                        'otmedia',
143                        'owlin',
144                        'owncloud',
145                        'panscient',
146                        'paper\.li',
147                        'parsijoo',
148                        'protopage',
149                        'plukkie',
150                        'proximic',
151                        'pubsub',
152                        'python',
153                        'qirina',
154                        'qoshe',
155                        'qualidator',
156                        'qwantify',
157                        'rambler',
158                        'readability',
159                        'ruby',
160                        'sbsearch',
161                        'scoop\.it',
162                        'scooter',
163                        'scoutjet',
164                        'scrapy',
165                        'scrubby',
166                        'scrubbybloglines',
167                        'shareaholic',
168                        'shopwiki',
169                        'simplepie',
170                        'sistrix',
171                        'sitechecker',
172                        'siteexplorer',
173                        'snapshot',
174                        'sogou',
175                        'special_archiver',
176                        'speedy',
177                        'spinn3r',
178                        'spreadtrum',
179                        'steeler',
180                        'subscriber',
181                        'suma',
182                        'superdownloads',
183                        'svenska-webbsido',
184                        'teoma',
185                        'the knowledge AI',
186                        'thumbshots',
187                        'tineye',
188                        'traackr',
189                        'trendiction',
190                        'trendsmap',
191                        'tweetedtimes',
192                        'tweetmeme',
193                        'universalfeedparser',
194                        'uaslinkchecker',
195                        'undrip',
196                        'unwindfetchor',
197                        'upday',
198                        'vedma',
199                        'vkshare',
200                        'vm',
201                        'wch',
202                        'webalta',
203                        'webcookies',
204                        'webparser',
205                        'webthumbnail',
206                        'wesee',
207                        'wise-guys',
208                        'woko',
209                        'wordpress',
210                        'wotbox',
211                        'y!j-bri',
212                        'y!j-bro',
213                        'y!j-brw',
214                        'y!j-bsc',
215                        'yahoo',
216                        'yahoo!',
217                        'yahooysmcm',
218                        'ymobactus',
219                        'yats',
220                        'yeti',
221                        'zeerch'
222                )) . ',i',
223                (string)$_SERVER['HTTP_USER_AGENT'])
224        );
225}
226if (!defined('_IS_BOT_FRIEND')){
227        define('_IS_BOT_FRIEND',
228                isset($_SERVER['HTTP_USER_AGENT'])
229                and preg_match(',' . implode ('|', array(
230                        'facebookexternalhit',
231                        'flipboardproxy',
232                        'wordpress'
233                )) . ',i',
234                (string)$_SERVER['HTTP_USER_AGENT'])
235        );
236}
237
238/*
239 * Interdit de passer une variable id_article (ou id_xxx) qui ne
240 * soit pas numérique (ce qui bloque l'exploitation de divers trous
241 * de sécurité, dont celui de toutes les versions < 1.8.2f)
242 * (sauf pour id_table, qui n'est pas numérique jusqu'à [5743])
243 * (id_base est une variable de la config des widgets de WordPress)
244 */
245foreach ($_GET as $var => $val)
246        if ($_GET[$var] and strncmp($var, "id_", 3) == 0
247        and !in_array($var, array('id_table', 'id_base')))
248                $_GET[$var] = is_array($_GET[$var])?@array_map('intval', $_GET[$var]):intval($_GET[$var]);
249foreach ($_POST as $var => $val)
250        if ($_POST[$var] and strncmp($var, "id_", 3) == 0
251        and !in_array($var, array('id_table', 'id_base')))
252                $_POST[$var] = is_array($_POST[$var])?@array_map('intval', $_POST[$var]):intval($_POST[$var]);
253foreach ($GLOBALS as $var => $val)
254        if ($GLOBALS[$var] and strncmp($var, "id_", 3) == 0
255        and !in_array($var, array('id_table', 'id_base')))
256                $GLOBALS[$var] = is_array($GLOBALS[$var])?@array_map('intval', $GLOBALS[$var]):intval($GLOBALS[$var]);
257
258/*
259 * Interdit la variable $cjpeg_command, qui était utilisée sans
260 * précaution dans certaines versions de dev (1.8b2 -> 1.8b5)
261 */
262$cjpeg_command = '';
263
264/*
265 * Contrôle de quelques variables (XSS)
266 */
267foreach(array('lang', 'var_recherche', 'aide', 'var_lang_r', 'lang_r', 'var_ajax_ancre', 'nom_fichier') as $var) {
268        if (isset($_GET[$var]))
269                $_REQUEST[$var] = $GLOBALS[$var] = $_GET[$var] = preg_replace(',[^\w\,/#&;-]+,', ' ', (string)$_GET[$var]);
270        if (isset($_POST[$var]))
271                $_REQUEST[$var] = $GLOBALS[$var] = $_POST[$var] = preg_replace(',[^\w\,/#&;-]+,', ' ', (string)$_POST[$var]);
272}
273
274/*
275 * Filtre l'accès à spip_acces_doc (injection SQL en 1.8.2x)
276 */
277if (preg_match(',^(.*/)?spip_acces_doc\.,', (string)$_SERVER['REQUEST_URI'])) {
278        $file = addslashes((string)$_GET['file']);
279}
280
281/*
282 * Pas d'inscription abusive
283 */
284if (isset($_REQUEST['mode']) and isset($_REQUEST['page'])
285and !in_array($_REQUEST['mode'], array("6forum", "1comite"))
286and $_REQUEST['page'] == "identifiants")
287        $ecran_securite_raison = "identifiants";
288
289/*
290 * Agenda joue à l'injection php
291 */
292if (isset($_REQUEST['partie_cal'])
293and $_REQUEST['partie_cal'] !== htmlentities((string)$_REQUEST['partie_cal']))
294        $ecran_securite_raison = "partie_cal";
295if (isset($_REQUEST['echelle'])
296and $_REQUEST['echelle'] !== htmlentities((string)$_REQUEST['echelle']))
297        $ecran_securite_raison = "echelle";
298
299/*
300 * Espace privé
301 */
302if (isset($_REQUEST['exec'])
303and !preg_match(',^[\w-]+$,', (string)$_REQUEST['exec']))
304        $ecran_securite_raison = "exec";
305if (isset($_REQUEST['cherche_auteur'])
306and preg_match(',[<],', (string)$_REQUEST['cherche_auteur']))
307        $ecran_securite_raison = "cherche_auteur";
308if (isset($_REQUEST['exec'])
309and $_REQUEST['exec'] == 'auteurs'
310and preg_match(',[<],', (string)$_REQUEST['recherche']))
311        $ecran_securite_raison = "recherche";
312if (isset($_REQUEST['exec'])
313and $_REQUEST['exec'] == 'info_plugin'
314and preg_match(',[<],', (string)$_REQUEST['plugin']))
315        $ecran_securite_raison = "plugin";
316if (isset($_REQUEST['exec'])
317and $_REQUEST['exec'] == 'puce_statut'
318and isset($_REQUEST['id'])
319and !intval($_REQUEST['id']))
320        $ecran_securite_raison = "puce_statut";
321if (isset($_REQUEST['action'])
322and $_REQUEST['action'] == 'configurer') {
323        if (@file_exists('inc_version.php')
324        or @file_exists('ecrire/inc_version.php')) {
325                function action_configurer() {
326                        include_spip('inc/autoriser');
327                        if(!autoriser('configurer', _request('configuration'))) {
328                                include_spip('inc/minipres');
329                                echo minipres(_T('info_acces_interdit'));
330                                exit;
331                        }
332                        require _DIR_RESTREINT.'action/configurer.php';
333                        action_configurer_dist();
334                }
335        }
336}
337
338/*
339 * Bloque les requêtes contenant %00 (manipulation d'include)
340 */
341if (strpos(
342        @get_magic_quotes_gpc() ?
343                stripslashes(serialize($_REQUEST)) : serialize($_REQUEST),
344        chr(0)
345) !== false)
346        $ecran_securite_raison = "%00";
347
348/*
349 * Bloque les requêtes fond=formulaire_
350 */
351if (isset($_REQUEST['fond'])
352and preg_match(',^formulaire_,i', $_REQUEST['fond']))
353        $ecran_securite_raison = "fond=formulaire_";
354
355/*
356 * Bloque les requêtes du type ?GLOBALS[type_urls]=toto (bug vieux php)
357 */
358if (isset($_REQUEST['GLOBALS']))
359        $ecran_securite_raison = "GLOBALS[GLOBALS]";
360
361/*
362 * Bloque les requêtes des bots sur:
363 * les agenda
364 * les paginations entremélées
365 */
366if (_IS_BOT and (
367        (isset($_REQUEST['echelle']) and isset($_REQUEST['partie_cal']) and isset($_REQUEST['type']))
368        or (strpos((string)$_SERVER['REQUEST_URI'], 'debut_') and preg_match(',[?&]debut_.*&debut_,', (string)$_SERVER['REQUEST_URI']))
369)
370)
371        $ecran_securite_raison = "robot agenda/double pagination";
372
373/*
374 * Bloque une vieille page de tests de CFG (<1.11)
375 * Bloque un XSS sur une page inexistante
376 */
377if (isset($_REQUEST['page'])) {
378        if ($_REQUEST['page'] == 'test_cfg')
379                $ecran_securite_raison = "test_cfg";
380        if ($_REQUEST['page'] !== htmlspecialchars((string)$_REQUEST['page']))
381                $ecran_securite_raison = "xsspage";
382        if ($_REQUEST['page'] == '404'
383        and isset($_REQUEST['erreur']))
384                $ecran_securite_raison = "xss404";
385}
386
387/*
388 * XSS par array
389 */
390foreach (array('var_login') as $var)
391if (isset($_REQUEST[$var]) and is_array($_REQUEST[$var]))
392        $ecran_securite_raison = "xss ".$var;
393
394/*
395 * Parade antivirale contre un cheval de troie
396 */
397if (!function_exists('tmp_lkojfghx')) {
398        function tmp_lkojfghx() {}
399        function tmp_lkojfghx2($a = 0, $b = 0, $c = 0, $d = 0) {
400                // si jamais on est arrivé ici sur une erreur php
401                // et qu'un autre gestionnaire d'erreur est défini, l'appeller
402                if ($b && $GLOBALS['tmp_xhgfjokl'])
403                        call_user_func($GLOBALS['tmp_xhgfjokl'], $a, $b, $c, $d);
404        }
405}
406if (isset($_POST['tmp_lkojfghx3']))
407        $ecran_securite_raison = "gumblar";
408
409/*
410 * Outils XML mal sécurisés < 2.0.9
411 */
412if (isset($_REQUEST['transformer_xml']))
413        $ecran_securite_raison = "transformer_xml";
414
415/*
416 * Outils XML mal sécurisés again
417 */
418if (isset($_REQUEST['var_url']) and $_REQUEST['var_url'] and isset($_REQUEST['exec']) and $_REQUEST['exec']=='valider_xml'){
419        $url = trim($_REQUEST['var_url']);
420        if (strncmp($url,'/',1)==0
421          or (($p=strpos($url,'..'))!==false AND strpos($url,'..',$p+3)!==false)
422          or (($p=strpos($url,'..'))!==false AND strpos($url,'IMG',$p+3)!==false)
423                or (strpos($url,'://')!==false or strpos($url,':\\')!==false)) {
424                $ecran_securite_raison = 'URL interdite pour var_url';
425        }
426}
427
428/*
429 * Sauvegarde mal securisée < 2.0.9
430 */
431if (isset($_REQUEST['nom_sauvegarde'])
432and strstr((string)$_REQUEST['nom_sauvegarde'], '/'))
433        $ecran_securite_raison = 'nom_sauvegarde manipulee';
434if (isset($_REQUEST['znom_sauvegarde'])
435and strstr((string)$_REQUEST['znom_sauvegarde'], '/'))
436        $ecran_securite_raison = 'znom_sauvegarde manipulee';
437
438
439/*
440 * op permet des inclusions arbitraires ;
441 * on vérifie 'page' pour ne pas bloquer ... drupal
442 */
443if (isset($_REQUEST['op']) and isset($_REQUEST['page'])
444and $_REQUEST['op'] !== preg_replace('/[^\-\w]/', '', $_REQUEST['op']))
445        $ecran_securite_raison = 'op';
446
447/*
448 * Forms & Table ne se méfiait pas assez des uploads de fichiers
449 */
450if (count($_FILES)){
451        foreach($_FILES as $k => $v){
452                 if (preg_match(',^fichier_\d+$,', $k)
453                 and preg_match(',\.php,i', $v['name']))
454                        unset($_FILES[$k]);
455        }
456}
457/*
458 * et Contact trop laxiste avec une variable externe
459 * on bloque pas le post pour eviter de perdre des donnees mais on unset la variable et c'est tout
460 */
461if (isset($_REQUEST['pj_enregistrees_nom']) and $_REQUEST['pj_enregistrees_nom']){
462        unset($_REQUEST['pj_enregistrees_nom']);
463        unset($_GET['pj_enregistrees_nom']);
464        unset($_POST['pj_enregistrees_nom']);
465}
466
467/*
468 * reinstall=oui un peu trop permissif
469 */
470if (isset($_REQUEST['reinstall'])
471and $_REQUEST['reinstall'] == 'oui')
472        $ecran_securite_raison = 'reinstall=oui';
473
474/*
475 * Échappement xss referer
476 */
477if (isset($_SERVER['HTTP_REFERER']))
478        $_SERVER['HTTP_REFERER'] = strtr($_SERVER['HTTP_REFERER'], '<>"\'', '[]##');
479
480
481/*
482 * Echappement HTTP_X_FORWARDED_HOST
483 */
484if (isset($_SERVER['HTTP_X_FORWARDED_HOST']))
485        $_SERVER['HTTP_X_FORWARDED_HOST'] = strtr($_SERVER['HTTP_X_FORWARDED_HOST'], "<>?\"\{\}\$'` \r\n", '____________');
486
487
488/*
489 * Réinjection des clés en html dans l'admin r19561
490 */
491if (strpos($_SERVER['REQUEST_URI'], "ecrire/") !== false){
492        $zzzz = implode("", array_keys($_REQUEST));
493        if (strlen($zzzz) != strcspn($zzzz, '<>"\''))
494                $ecran_securite_raison = 'Cle incorrecte en $_REQUEST';
495}
496
497/*
498 * Injection par connect
499 */
500if (isset($_REQUEST['connect'])
501        and
502        // cas qui permettent de sortir d'un commentaire PHP
503        (strpos($_REQUEST['connect'], "?") !== false
504         or strpos($_REQUEST['connect'], "<") !== false
505         or strpos($_REQUEST['connect'], ">") !== false
506         or strpos($_REQUEST['connect'], "\n") !== false
507         or strpos($_REQUEST['connect'], "\r") !== false)
508        ) {
509        $ecran_securite_raison = "malformed connect argument";
510}
511
512/*
513 * S'il y a une raison de mourir, mourons
514 */
515if (isset($ecran_securite_raison)) {
516        header("HTTP/1.0 403 Forbidden");
517        header("Expires: Wed, 11 Jan 1984 05:00:00 GMT");
518        header("Cache-Control: no-cache, must-revalidate");
519        header("Pragma: no-cache");
520        header("Content-Type: text/html");
521        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>");
522}
523
524/*
525 * Un filtre filtrer_entites securise
526 */
527if (!function_exists('filtre_filtrer_entites_dist')) {
528        function filtre_filtrer_entites_dist($t) {
529                include_spip('inc/texte');
530                return interdire_scripts(filtrer_entites($t));
531        }
532}
533
534
535/*
536 * Fin sécurité
537 */
538
539
540
541/*
542 * Bloque les bots quand le load déborde
543 */
544if (!defined('_ECRAN_SECURITE_LOAD'))
545        define('_ECRAN_SECURITE_LOAD', 4);
546
547if (
548        defined('_ECRAN_SECURITE_LOAD')
549        and _ECRAN_SECURITE_LOAD > 0
550        and _IS_BOT
551        and !_IS_BOT_FRIEND
552        and $_SERVER['REQUEST_METHOD'] === 'GET'
553        and (
554                (function_exists('sys_getloadavg')
555                  and $load = sys_getloadavg()
556                  and is_array($load)
557                  and $load = array_shift($load)
558                )
559                or
560                (@is_readable('/proc/loadavg')
561                  and $load = file_get_contents('/proc/loadavg')
562                  and $load = floatval($load)
563                )
564        )
565        and $load > _ECRAN_SECURITE_LOAD // eviter l'evaluation suivante si de toute facon le load est inferieur a la limite
566        and rand(0, $load * $load) > _ECRAN_SECURITE_LOAD * _ECRAN_SECURITE_LOAD
567) {
568        header("HTTP/1.0 503 Service Unavailable");
569        header("Retry-After: 300");
570        header("Expires: Wed, 11 Jan 1984 05:00:00 GMT");
571        header("Cache-Control: no-cache, must-revalidate");
572        header("Pragma: no-cache");
573        header("Content-Type: text/html");
574        die("<html><title>Status 503: Site temporarily unavailable</title><body><h1>Status 503</h1><p>Site temporarily unavailable (load average $load)</p></body></html>");
575}
Note: See TracBrowser for help on using the repository browser.