[SPIP] ~maj v3.0.14-->v3.0.17
[ptitvelo/web/www.git] / www / config / ecran_securite.php
1 <?php
2
3 /*
4 * ecran_securite.php
5 * ------------------
6 */
7
8 define('_ECRAN_SECURITE', '1.1.9'); // 2014-03-13
9
10 /*
11 * Documentation : http://www.spip.net/fr_article4200.html
12 */
13
14 /*
15 * Test utilisateur
16 */
17 if (isset($_GET['test_ecran_securite']))
18 $ecran_securite_raison = 'test '._ECRAN_SECURITE;
19
20 /*
21 * Détecteur de robot d'indexation
22 */
23 if (!defined('_IS_BOT'))
24 define('_IS_BOT',
25 isset($_SERVER['HTTP_USER_AGENT'])
26 AND preg_match(
27 // mots generiques
28 ',bot|slurp|crawler|spider|webvac|yandex|'
29 // UA plus cibles
30 . '80legs|accoona|AltaVista|ASPSeek|Baidu|Charlotte|EC2LinkFinder|eStyle|Google|INA dlweb|Java VM|LiteFinder|Lycos|Rambler|Scooter|ScrubbyBloglines|Yahoo|Yeti'
31 . ',i',(string) $_SERVER['HTTP_USER_AGENT'])
32 );
33
34 /*
35 * Interdit de passer une variable id_article (ou id_xxx) qui ne
36 * soit pas numérique (ce qui bloque l'exploitation de divers trous
37 * de sécurité, dont celui de toutes les versions < 1.8.2f)
38 * (sauf pour id_table, qui n'est pas numérique jusqu'à [5743])
39 */
40 foreach ($_GET as $var => $val)
41 if ($_GET[$var] AND strncmp($var,"id_",3)==0 AND $var!='id_table')
42 $_GET[$var] = is_array($_GET[$var])?@array_map('intval',$_GET[$var]):intval($_GET[$var]);
43 foreach ($_POST as $var => $val)
44 if ($_POST[$var] AND strncmp($var,"id_",3)==0 AND $var!='id_table')
45 $_POST[$var] = is_array($_POST[$var])?@array_map('intval',$_POST[$var]):intval($_POST[$var]);
46 foreach ($GLOBALS as $var => $val)
47 if ($GLOBALS[$var] AND strncmp($var,"id_",3)==0 AND $var!='id_table')
48 $GLOBALS[$var] = is_array($GLOBALS[$var])?@array_map('intval',$GLOBALS[$var]):intval($GLOBALS[$var]);
49
50 /*
51 * Interdit la variable $cjpeg_command, qui était utilisée sans
52 * précaution dans certaines versions de dev (1.8b2 -> 1.8b5)
53 */
54 $cjpeg_command='';
55
56 /*
57 * Contrôle de quelques variables (XSS)
58 */
59 foreach(array('lang', 'var_recherche', 'aide', 'var_lang_r', 'lang_r', 'var_ajax_ancre') as $var) {
60 if (isset($_GET[$var]))
61 $_REQUEST[$var] = $GLOBALS[$var] = $_GET[$var] = preg_replace(',[^\w\,/#&;-]+,',' ',(string)$_GET[$var]);
62 if (isset($_POST[$var]))
63 $_REQUEST[$var] = $GLOBALS[$var] = $_POST[$var] = preg_replace(',[^\w\,/#&;-]+,',' ',(string)$_POST[$var]);
64 }
65
66 /*
67 * Filtre l'accès à spip_acces_doc (injection SQL en 1.8.2x)
68 */
69 if (preg_match(',^(.*/)?spip_acces_doc\.,', (string)$_SERVER['REQUEST_URI'])) {
70 $file = addslashes((string)$_GET['file']);
71 }
72
73 /*
74 * Pas d'inscription abusive
75 */
76 if (isset($_REQUEST['mode']) AND isset($_REQUEST['page'])
77 AND !in_array($_REQUEST['mode'],array("6forum","1comite"))
78 AND $_REQUEST['page'] == "identifiants")
79 $ecran_securite_raison = "identifiants";
80
81 /*
82 * Agenda joue à l'injection php
83 */
84 if (isset($_REQUEST['partie_cal'])
85 AND $_REQUEST['partie_cal'] !== htmlentities((string)$_REQUEST['partie_cal']))
86 $ecran_securite_raison = "partie_cal";
87 if (isset($_REQUEST['echelle'])
88 AND $_REQUEST['echelle'] !== htmlentities((string)$_REQUEST['echelle']))
89 $ecran_securite_raison = "echelle";
90
91 /*
92 * Espace privé
93 */
94 if (isset($_REQUEST['exec'])
95 AND !preg_match(',^[\w-]+$,', (string)$_REQUEST['exec']))
96 $ecran_securite_raison = "exec";
97 if (isset($_REQUEST['cherche_auteur'])
98 AND preg_match(',[<],', (string)$_REQUEST['cherche_auteur']))
99 $ecran_securite_raison = "cherche_auteur";
100 if (isset($_REQUEST['exec'])
101 AND $_REQUEST['exec'] == 'auteurs'
102 AND preg_match(',[<],', (string)$_REQUEST['recherche']))
103 $ecran_securite_raison = "recherche";
104 if (isset($_REQUEST['action'])
105 AND $_REQUEST['action'] == 'configurer') {
106 if (@file_exists('inc_version.php')
107 OR @file_exists('ecrire/inc_version.php')) {
108 function action_configurer() {
109 include_spip('inc/autoriser');
110 if(!autoriser('configurer', _request('configuration'))) {
111 include_spip('inc/minipres');
112 echo minipres(_T('info_acces_interdit'));
113 exit;
114 }
115 require _DIR_RESTREINT.'action/configurer.php';
116 action_configurer_dist();
117 }
118 }
119 }
120
121 /*
122 * Bloque les requêtes contenant %00 (manipulation d'include)
123 */
124 if (strpos(
125 @get_magic_quotes_gpc() ?
126 stripslashes(serialize($_REQUEST)) : serialize($_REQUEST),
127 chr(0)
128 ) !== false)
129 $ecran_securite_raison = "%00";
130
131 /*
132 * Bloque les requêtes fond=formulaire_
133 */
134 if (isset($_REQUEST['fond'])
135 AND preg_match(',^formulaire_,i', $_REQUEST['fond']))
136 $ecran_securite_raison = "fond=formulaire_";
137
138 /*
139 * Bloque les requêtes du type ?GLOBALS[type_urls]=toto (bug vieux php)
140 */
141 if (isset($_REQUEST['GLOBALS']))
142 $ecran_securite_raison = "GLOBALS[GLOBALS]";
143
144 /*
145 * Bloque les requêtes des bots sur:
146 * les agenda
147 * les paginations entremélées
148 */
149 if (_IS_BOT AND (
150 (isset($_REQUEST['echelle']) AND isset($_REQUEST['partie_cal']) AND isset($_REQUEST['type']))
151 OR (strpos((string)$_SERVER['REQUEST_URI'],'debut_') AND preg_match(',[?&]debut_.*&debut_,', (string)$_SERVER['REQUEST_URI']))
152 )
153 )
154 $ecran_securite_raison = "robot agenda/double pagination";
155
156 /*
157 * Bloque une vieille page de tests de CFG (<1.11)
158 * Bloque un XSS sur une page inexistante
159 */
160 if (isset($_REQUEST['page'])) {
161 if ($_REQUEST['page']=='test_cfg')
162 $ecran_securite_raison = "test_cfg";
163 if ($_REQUEST['page'] !== htmlspecialchars((string)$_REQUEST['page']))
164 $ecran_securite_raison = "xsspage";
165 if ($_REQUEST['page'] == '404'
166 AND isset($_REQUEST['erreur']))
167 $ecran_securite_raison = "xss404";
168 }
169
170 /*
171 * XSS par array
172 */
173 foreach (array('var_login') as $var)
174 if (isset($_REQUEST[$var]) AND is_array($_REQUEST[$var]))
175 $ecran_securite_raison = "xss ".$var;
176
177 /*
178 * Parade antivirale contre un cheval de troie
179 */
180 if (!function_exists('tmp_lkojfghx')) {
181 function tmp_lkojfghx() {}
182 function tmp_lkojfghx2($a=0, $b=0, $c=0, $d=0) {
183 // si jamais on est arrivé ici sur une erreur php
184 // et qu'un autre gestionnaire d'erreur est défini, l'appeller
185 if ($b&&$GLOBALS['tmp_xhgfjokl'])
186 call_user_func($GLOBALS['tmp_xhgfjokl'],$a,$b,$c,$d);
187 }
188 }
189 if (isset($_POST['tmp_lkojfghx3']))
190 $ecran_securite_raison = "gumblar";
191
192 /*
193 * Outils XML mal sécurisés < 2.0.9
194 */
195 if (isset($_REQUEST['transformer_xml']))
196 $ecran_securite_raison = "transformer_xml";
197
198 /*
199 * Sauvegarde mal securisée < 2.0.9
200 */
201 if (isset($_REQUEST['nom_sauvegarde'])
202 AND strstr((string)$_REQUEST['nom_sauvegarde'], '/'))
203 $ecran_securite_raison = 'nom_sauvegarde manipulee';
204 if (isset($_REQUEST['znom_sauvegarde'])
205 AND strstr((string)$_REQUEST['znom_sauvegarde'], '/'))
206 $ecran_securite_raison = 'znom_sauvegarde manipulee';
207
208
209 /*
210 * op permet des inclusions arbitraires ;
211 * on vérifie 'page' pour ne pas bloquer ... drupal
212 */
213 if (isset($_REQUEST['op']) AND isset($_REQUEST['page'])
214 AND $_REQUEST['op'] !== preg_replace('/[^\-\w]/', '', $_REQUEST['op']))
215 $ecran_securite_raison = 'op';
216
217 /*
218 * Forms & Table ne se méfiait pas assez des uploads de fichiers
219 */
220 if (count($_FILES)){
221 foreach($_FILES as $k=>$v){
222 if (preg_match(',^fichier_\d+$,',$k)
223 AND preg_match(',\.php,i',$v['name']))
224 unset($_FILES[$k]);
225 }
226 }
227
228 /*
229 * reinstall=oui un peu trop permissif
230 */
231 if (isset($_REQUEST['reinstall'])
232 AND $_REQUEST['reinstall'] == 'oui')
233 $ecran_securite_raison = 'reinstall=oui';
234
235 /*
236 * Échappement xss referer
237 */
238 if (isset($_SERVER['HTTP_REFERER']))
239 $_SERVER['HTTP_REFERER'] = strtr($_SERVER['HTTP_REFERER'], '<>"\'', '[]##');
240
241 /*
242 * Réinjection des clés en html dans l'admin r19561
243 */
244 if (strpos($_SERVER['REQUEST_URI'],"ecrire/")!==false){
245 $zzzz=implode("",array_keys($_REQUEST));
246 if (strlen($zzzz)!=strcspn($zzzz,'<>"\''))
247 $ecran_securite_raison = 'Cle incorrecte en $_REQUEST';
248 }
249
250 /*
251 * Injection par connect
252 */
253 if (isset($_REQUEST['connect'])
254 AND
255 // cas qui permettent de sortir d'un commentaire PHP
256 (strpos($_REQUEST['connect'], "?")!==false
257 OR strpos($_REQUEST['connect'], "<")!==false
258 OR strpos($_REQUEST['connect'], ">")!==false
259 OR strpos($_REQUEST['connect'], "\n")!==false
260 OR strpos($_REQUEST['connect'], "\r")!==false)
261 ) {
262 $ecran_securite_raison = "malformed connect argument";
263 }
264
265 /*
266 * S'il y a une raison de mourir, mourons
267 */
268 if (isset($ecran_securite_raison)) {
269 header("HTTP/1.0 403 Forbidden");
270 header("Expires: Wed, 11 Jan 1984 05:00:00 GMT");
271 header("Cache-Control: no-cache, must-revalidate");
272 header("Pragma: no-cache");
273 header("Content-Type: text/html");
274 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>");
275 }
276
277 /*
278 * Fin sécurité
279 */
280
281
282
283 /*
284 * Bloque les bots quand le load déborde
285 */
286 if (!defined('_ECRAN_SECURITE_LOAD'))
287 define('_ECRAN_SECURITE_LOAD', 4);
288
289 if (
290 defined('_ECRAN_SECURITE_LOAD')
291 AND _ECRAN_SECURITE_LOAD>0
292 AND _IS_BOT
293 AND $_SERVER['REQUEST_METHOD'] === 'GET'
294 AND (
295 (function_exists('sys_getloadavg')
296 AND $load = sys_getloadavg()
297 AND is_array($load)
298 AND $load = array_shift($load)
299 )
300 OR
301 (@is_readable('/proc/loadavg')
302 AND $load = file_get_contents('/proc/loadavg')
303 AND $load = floatval($load)
304 )
305 )
306 AND $load > _ECRAN_SECURITE_LOAD // eviter l'evaluation suivante si de toute facon le load est inferieur a la limite
307 AND rand(0, $load*$load) > _ECRAN_SECURITE_LOAD*_ECRAN_SECURITE_LOAD
308 ) {
309 header("HTTP/1.0 503 Service Unavailable");
310 header("Retry-After: 300");
311 header("Expires: Wed, 11 Jan 1984 05:00:00 GMT");
312 header("Cache-Control: no-cache, must-revalidate");
313 header("Pragma: no-cache");
314 header("Content-Type: text/html");
315 die("<html><title>Status 503: Site temporarily unavailable</title><body><h1>Status 503</h1><p>Site temporarily unavailable (load average $load)</p></body></html>");
316 }
317
318
319 ?>