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[] = cString::toLowerCase($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: 210:
211: public function checkParams() {
212:
213: if ((!$this->checkGetParams()) || (!$this->checkPostParams() || (!$this->checkCookieParams()))) {
214: $this->logHackTrial();
215:
216: if ($this->_mode == 'stop') {
217: ob_end_clean();
218: $msg = 'Parameter check failed! (%s = %s %s %s)';
219:
220: $msg = sprintf($msg, htmlentities($this->_failure), htmlentities($_GET[$this->_failure]), htmlentities($_POST[$this->_failure]), htmlentities($_COOKIE[$this->_failure]));
221: die($msg);
222: }
223: }
224:
225: return true;
226: }
227:
228: 229: 230: 231: 232: 233: 234:
235: public function checkGetParams() {
236:
237: return $this->checkArray($_GET, 'GET');
238: }
239:
240: 241: 242: 243: 244: 245: 246:
247: public function checkPostParams() {
248:
249: return $this->checkArray($_POST, 'POST');
250: }
251:
252: 253: 254: 255: 256: 257: 258:
259: public function checkCookieParams() {
260:
261: return $this->checkArray($_COOKIE, 'COOKIE');
262: }
263:
264:
265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279:
280: public function checkParameter($type, $key, $value) {
281:
282: $result = false;
283:
284: if (in_array(cString::toLowerCase($key), $this->_blacklist)) {
285: return false;
286: }
287:
288: if (in_array(cString::toUpperCase($type), array(
289: 'GET',
290: 'POST',
291: 'COOKIE'
292: ))) {
293: if (!isset($this->_check[$type][$key]) && (is_null($value) || empty($value))) {
294:
295: $result = true;
296: } elseif (isset($this->_check[$type][$key])) {
297:
298: $result = preg_match($this->_check[$type][$key], $value);
299: } else {
300:
301: $result = true;
302: }
303: }
304:
305: return $result;
306: }
307:
308: 309: 310: 311: 312: 313:
314: public function getBadParameter() {
315:
316: return $this->_failure;
317: }
318:
319: 320: 321: 322: 323: 324:
325: protected function logHackTrial() {
326:
327: if ($this->_log === true && !empty($this->_logPath)) {
328: $content = date('Y-m-d H:i:s') . ' ';
329: $content .= $_SERVER['REMOTE_ADDR'] . str_repeat(' ', 17 - cString::getStringLength($_SERVER['REMOTE_ADDR'])) . "\n";
330: $content .= ' Query String: ' . $_SERVER['QUERY_STRING'] . "\n";
331: $content .= ' Bad parameter: ' . $this->getBadParameter() . "\n";
332: $content .= ' POST array: ' . print_r($_POST, true) . "\n";
333: $content .= ' GET array: ' . print_r($_GET, true) . "\n";
334: $content .= ' COOKIE array: ' . print_r($_COOKIE, true) . "\n";
335: cFileHandler::write($this->_logPath, $content, true);
336: } elseif ($this->_mode == 'continue') {
337: echo "\n<br>VIOLATION: URL contains invalid or undefined paramaters! URL: '" . conHtmlentities($_SERVER['QUERY_STRING']) . "' <br>\n";
338: }
339: }
340:
341: 342: 343: 344: 345: 346: 347:
348: public static function cleanParameter($param) {
349:
350: $charsToReplace = array(
351: '<', '>', '?', '&', '$', '{', '}', '(', ')'
352: );
353:
354: foreach ($charsToReplace as $char) {
355: $param = str_replace($char, '', $param);
356: }
357:
358: return $param;
359: }
360:
361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371:
372: protected function checkArray($arr, $type) {
373:
374: $result = true;
375:
376: foreach ($arr as $key => $value) {
377: if (!$this->checkParameter(cString::toUpperCase($type), $key, $value)) {
378: $this->_failure = $key;
379: $result = false;
380: break;
381: }
382: }
383:
384: return $result;
385: }
386:
387: }
388: