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