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