1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14:
15: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
16:
17: 18: 19: 20: 21: 22:
23: class cRequestValidator {
24:
25: 26: 27: 28: 29:
30: private static $_instance = null;
31:
32: 33: 34: 35: 36:
37: protected $_logPath;
38:
39: 40: 41: 42: 43:
44: protected $_log = true;
45:
46: 47: 48: 49: 50:
51: protected $_configPath;
52:
53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63:
64: protected $_check = array();
65:
66: 67: 68: 69: 70: 71:
72: protected $_blacklist = array();
73:
74: 75: 76: 77: 78:
79: protected $_failure = '';
80:
81: 82: 83: 84: 85:
86: protected $_mode = '';
87:
88: 89: 90: 91: 92:
93: const CHECK_INTEGER = '/^[0-9]*$/';
94:
95: 96: 97: 98: 99:
100: const CHECK_PRIMITIVESTRING = '/^[a-zA-Z0-9 -_]*$/';
101:
102: 103: 104: 105: 106:
107: const CHECK_STRING = '/^[\w0-9 -_]*$/';
108:
109: 110: 111: 112: 113:
114: const CHECK_HASH32 = '/^[a-zA-Z0-9]{32}$/';
115:
116: 117: 118: 119: 120:
121: const CHECK_BELANG = '/^[a-z]{2}_[A-Z]{2}$/';
122:
123: 124: 125: 126: 127:
128: const CHECK_AREASTRING = '/^[a-zA-Z_]*$/';
129:
130: 131: 132: 133: 134:
135: const CHECK_PATHSTRING = '!([*]*\/)|(dbfs:\/[*]*)|(dbfs:)|(^)$!';
136:
137: 138: 139: 140: 141: 142: 143: 144: 145:
146: private function __construct() {
147:
148:
149: global $bLog, $sMode, $aCheck, $aBlacklist;
150:
151:
152: $installationPath = str_replace('\\', '/', realpath(dirname(__FILE__) . '/../..'));
153: $configPath = $installationPath . '/data/config/' . CON_ENVIRONMENT;
154:
155: $this->_logPath = $installationPath . '/data/logs/security.txt';
156:
157:
158: if (cFileHandler::exists($configPath . '/config.http_check.php')) {
159: $this->_configPath = $configPath;
160: } else {
161: throw new cFileNotFoundException('Could not load cRequestValidator configuration! (invalid path) ' . $configPath . '/config.http_check.php');
162: }
163:
164:
165: require($this->_configPath . '/config.http_check.php');
166:
167:
168: if (cFileHandler::exists($this->_configPath . '/config.http_check.local.php')) {
169: require($this->_configPath . '/config.http_check.local.php');
170: }
171:
172: $this->_log = $bLog;
173: $this->_mode = $sMode;
174:
175: if ($this->_log === true) {
176: if (empty($this->_logPath) || !is_writeable(dirname($this->_logPath))) {
177: $this->_log = false;
178: }
179: }
180:
181: $this->_check = $aCheck;
182: foreach ($aBlacklist as $elem) {
183: $this->_blacklist[] = strtolower($elem);
184: }
185: }
186:
187: 188: 189: 190: 191:
192: public static function getInstance() {
193:
194: if (self::$_instance === null) {
195: self::$_instance = new self();
196: }
197:
198: return self::$_instance;
199: }
200:
201: 202: 203: 204: 205: 206: 207: 208:
209: public function checkParams() {
210:
211: if ((!$this->checkGetParams()) || (!$this->checkPostParams() || (!$this->checkCookieParams()))) {
212: $this->logHackTrial();
213:
214: if ($this->_mode == 'stop') {
215: ob_end_clean();
216: $msg = 'Parameter check failed! (%s = %s %s %s)';
217:
218: $msg = sprintf($msg, htmlentities($this->_failure), htmlentities($_GET[$this->_failure]), htmlentities($_POST[$this->_failure]), htmlentities($_COOKIE[$this->_failure]));
219: die($msg);
220: }
221: }
222:
223: return true;
224: }
225:
226: 227: 228: 229: 230: 231: 232:
233: public function checkGetParams() {
234:
235: return $this->checkArray($_GET, 'GET');
236: }
237:
238: 239: 240: 241: 242: 243: 244:
245: public function checkPostParams() {
246:
247: return $this->checkArray($_POST, 'POST');
248: }
249:
250: 251: 252: 253: 254: 255: 256:
257: public function checkCookieParams() {
258:
259: return $this->checkArray($_COOKIE, 'COOKIE');
260: }
261:
262:
263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277:
278: public function checkParameter($type, $key, $value) {
279:
280: $result = false;
281:
282: if (in_array(strtolower($key), $this->_blacklist)) {
283: return false;
284: }
285:
286: if (in_array(strtoupper($type), array(
287: 'GET',
288: 'POST',
289: 'COOKIE'
290: ))) {
291: if (!isset($this->_check[$type][$key]) && (is_null($value) || empty($value))) {
292:
293: $result = true;
294: } elseif (isset($this->_check[$type][$key])) {
295:
296: $result = preg_match($this->_check[$type][$key], $value);
297: } else {
298:
299: $result = true;
300: }
301: }
302:
303: return $result;
304: }
305:
306: 307: 308: 309: 310: 311:
312: public function getBadParameter() {
313:
314: return $this->_failure;
315: }
316:
317: 318: 319: 320:
321: protected function logHackTrial() {
322:
323: if ($this->_log === true && !empty($this->_logPath)) {
324: $content = date('Y-m-d H:i:s') . ' ';
325: $content .= $_SERVER['REMOTE_ADDR'] . str_repeat(' ', 17 - strlen($_SERVER['REMOTE_ADDR'])) . "\n";
326: $content .= ' Query String: ' . $_SERVER['QUERY_STRING'] . "\n";
327: $content .= ' Bad parameter: ' . $this->getBadParameter() . "\n";
328: $content .= ' POST array: ' . print_r($_POST, true) . "\n";
329: $content .= ' GET array: ' . print_r($_GET, true) . "\n";
330: $content .= ' COOKIE array: ' . print_r($_COOKIE, true) . "\n";
331: cFileHandler::write($this->_logPath, $content, true);
332: } elseif ($this->_mode == 'continue') {
333: echo "\n<br>VIOLATION: URL contains invalid or undefined paramaters! URL: '" . conHtmlentities($_SERVER['QUERY_STRING']) . "' <br>\n";
334: }
335: }
336:
337: 338: 339: 340: 341: 342: 343:
344: public static function cleanParameter($param) {
345:
346: $charsToReplace = array(
347: '<', '>', '?', '&', '$', '{', '}', '(', ')'
348: );
349:
350: foreach ($charsToReplace as $char) {
351: $param = str_replace($char, '', $param);
352: }
353:
354: return $param;
355: }
356:
357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367:
368: protected function checkArray($arr, $type) {
369:
370: $result = true;
371:
372: foreach ($arr as $key => $value) {
373: if (!$this->checkParameter(strtoupper($type), $key, $value)) {
374: $this->_failure = $key;
375: $result = false;
376: break;
377: }
378: }
379:
380: return $result;
381: }
382:
383: }
384: