Da in den letzten Tagen vermehrt Versuche mit "SQL-Injections" festgestellt wurden, möchte ich die aktuelle Version meines "SQL-Injection-Filters" noch mal vorstellen. Dieser erweitert den Standard-Gambio "Input"-Filter, und untersucht "GET"-und "POST"-Parameter auf typische Muster solcher "SQL-Injections"-Versuche. Wenn ein solches Muster gefunden wird, dann wird das aus dem Parameter entfernt. Der Admin erhält einen entsprechenden Hinweis per eMail. Und die IP wird automatisch in die "GProtector"-Blacklist-Datei eingestellt, so dass der Angreifer nur einen Versuch hat! Ob der Filter allen Versuchen standhält kann ich nicht garantieren, der Erfindungsreichtum der Hacker ist enorm. Aber besser als nichts ist das allemal. Evtl. kann man ja gemeinsam bessere Muster (regular expressions) finden, um solche Versuche besser zu erkennen, auch wenn die Hacker sich Mühe geben, die möglichst zu verschleiern... Den Inhalt des anhängenden Archivs in die Shop-Root kopieren. Wie immer gilt: Anwendung auf das ausschließliche Risiko des Shopbetreibers. Es gibt keinerlei Gewährleistung. Erst in einem Testshop testen.
Das System ist so auf jeden Fall schon sehr gut, um die Scanner oder manuelles Herumprobieren auszubremsen. Wenn die Leute aber anfangen ihre SQL-Schlüsselwörter gezielt herumzukodieren, könnte das schwierig werden. Aber da müssen wir gemeinsam, wie du schon sagst, mit der Zeit noch ein paar Muster draufpacken. Was dagegen, wenn wir das so in den Core übernehmen?
Ich denke, dass man über regläre Ausdrücke das sehr verbessern kann. Statt nur auf "select" zu testen, könnte man mit der regex "/s.*e.*l.*e.*c.*t.* /i" ein "select" auch erkennen, wenn da Leer- oder andere Zeichen eingestreut werden, was diese Hacker ja auch gerne machen.. Nein.
Ich habe das mal umgestellt auf die Untersuchung der Parameter mit "regular expressions" statt reinem Textvergleich... Man kann dabei nach wie vor die Suchtexte normal definieren PHP: $this->sqlCommands=array( 'select ', 'select(', 'union ', 'from(', 'concat(', 'convert(' ); die Umwandlung in einen regulären Ausdruck wird automatisch gemacht. Damit kann man schon eine ganze Reihe weiterer Verschleierungen mit eingestreuten Leerzeichen in die SQL-Kommandos erkennen.
Mhhh, so richtig nicht! V2.2 Artikeldetailseite! http://www.indiv-style.de/de/Module/Gambio-GX2-PDF-Katalog-Deluxe-GX2-V2-1-2-2.html
Wo er Recht hat, hat er Recht... Versuche bitte mal diese Version: PHP: <?php/* --------------------------------------------------------------pt_sqli_InputFilter.php 2015-04-14 AvengerGambio GmbHhttp://www.gambio.deCopyright (c) 2013 Gambio GambioCopyright (c) 2015 Avenger, apprentice@gmx.deRemove SQL injection code from parametersReleased under the GNU General Public License--------------------------------------------------------------*/class pt_sqli_InputFilter extends pt_sqli_InputFilter_parent{ var $sqlPatterns; function __construct($tagsArray = array (), $attrArray = array (), $tagsMethod = 0, $attrMethod = 0, $xssAuto = 1) { $user_agent=$_SERVER['HTTP_USER_AGENT']; if (stripos($user_agent,'sqlmap/')!==false) { exit(); } $this->pattern_separator='.*'; $this->sqlPatterns=array( 'select ', 'select(', 'union ', 'from(', 'concat(', 'convert(' ); //Convert search strings to regex patterns... foreach ($this->sqlPatterns as $index=>$sqlPattern) { $pattern=''; for ($i=0;$i<strlen($sqlPattern);$i++) { $c=$sqlPattern[$i]; $pattern.=$c.'.*'; } $this->sqlPatterns[$index]=str_replace('(','\(',$pattern); } parent::__construct($tagsArray, $attrArray, $tagsMethod, $attrMethod, $xssAuto); } function process($source, $get=false) { // clean all elements in this array foreach ($source as $key=>$values) { if (!is_array($values)) { $values=array($values); } foreach ($values as $value) { $value=urldecode($value); foreach ($this->sqlPatterns as $index=>$sqlPattern) { $found_sql=preg_match('#'.$sqlPattern.'#i',$value); if ($found_sql) { //Auto-block IP! if (class_exists('GProtector')) { $gprotector=new GProtector(); $ip=$gprotector->get_user_ip();; if ($ip<>'127.0.0.1') { if (!IS_LOCAL_HOST) { require_once (DIR_FS_CATALOG.'includes/classes/class.phpmailer.php'); require_once (DIR_FS_INC.'xtc_php_mail.inc.php'); } if ($get) { $source_parameter='GET'; } else { $source_parameter='POST'; } $two_eol=PHP_EOL.PHP_EOL; $mail_body= date('d.m.Y, H:i:s').$two_eol. "SQL-Injection-Versuch von IP: $ip (".gethostbyaddr($ip).")".$two_eol. "In $source_parameter-Paramter '$key=$value;'"; $gprotector_blacklist_file=DIR_FS_DOCUMENT_ROOT.'GProtector/ip_blacklist.txt'; if (is_file($gprotector_blacklist_file)) { $gprotector_blacklist_content=trim(file_get_contents($gprotector_blacklist_file)); $add_to_blacklist=strpos($gprotector_blacklist_content,$ip)===false; } else { $add_to_blacklist=true; $gprotector_blacklist_content=''; } if ($add_to_blacklist) { if ($gprotector_blacklist_content) { $gprotector_blacklist_content.=PHP_EOL; } file_put_contents($gprotector_blacklist_file,$gprotector_blacklist_content.$ip); $mail_body.=$two_eol."Die IP '$ip' wurde in der Datei '$gprotector_blacklist_file' blockiert."; $mail_body.=$two_eol."Um diese Blockierung aufzuheben, den IP-Eintrag für '$ip' in der Datei '$gprotector_blacklist_file' entfernen."; } if (!IS_LOCAL_HOST) { $email_address=EMAIL_BILLING_ADDRESS; $email_billing_name=EMAIL_BILLING_NAME; $gm_mail_status = xtc_php_mail(EMAIL_BILLING_ADDRESS, EMAIL_BILLING_NAME, $email_address, $email_billing_name, '', $email_address, $email_billing_name, '', '', 'SQL-Injection-Versuch!!!', $mail_body, $mail_body); } exit(); //Terminate processing } } unset($source[$key]); } } } } return parent::process($source,$get); }}
@ Avenger ich habe mal die vorletzte Version in den 2.0.15.1 installiert, eben kam folgender Debug Report. Code: Level: WARNING(2) Message: urldecode() expects parameter 1 to be string, array given in /www/htdocs/xxxxxx/gambio/user_classes/overloads/InputFilter/pt_sqli_InputFilter.php:55 Backtrace: #0 urldecode called at [/www/htdocs/xxxxxx/gambio/user_classes/overloads/InputFilter/pt_sqli_InputFilter.php:55] #1 (#pt_sqli_InputFilter) process called at [/www/htdocs/xxxxxx/gambio/includes/application_top.php:231] #2 require called at [/www/htdocs/xxxxxx/gambio/gm_ajax.php:14] Context: Array ( [source] => Array ( [id] => Array ( [18] => 60 ) [products_qty] => 1 [products_id] => 128 [submit_target] => cart ) [get] => [key] => id [value] => Array ( [18] => 60 ) ) Session: No Session
Hi! Meine Shop-Version 2.1.5.2, mit Mobile Candy 1.0.8 Artikel mit Attributen, wenn ich solch einen Artikel in den Warenkorb lege und dann die Anzahl des zu bestellenden Artikels ändere und auf "aktualisieren" klicke, kommt bei mir folgende Fehlermeldung: Nehme ich den Input-Filter wieder raus, kommt die Fehlermeldung nicht mehr...
Wie ist es mit dieser Version: PHP: <?php/* --------------------------------------------------------------pt_sqli_InputFilter.php 2015-04-14 AvengerGambio GmbHhttp://www.gambio.deCopyright (c) 2013 Gambio GambioCopyright (c) 2015 Avenger, apprentice@gmx.deRemove SQL injection code from parametersReleased under the GNU General Public License--------------------------------------------------------------*/class pt_sqli_InputFilter extends pt_sqli_InputFilter_parent{ var $sqlPatterns; function __construct($tagsArray = array (), $attrArray = array (), $tagsMethod = 0, $attrMethod = 0, $xssAuto = 1) { $user_agent=$_SERVER['HTTP_USER_AGENT']; if (stripos($user_agent,'sqlmap/')!==false) { exit(); } $this->pattern_separator='.*'; $this->sqlPatterns=array(); $this->sqlStrings=array( 'select ', 'select(', 'union ', 'from(', 'concat(', 'convert(' ); //Convert search strings to regex patterns... foreach ($this->sqlStrings as $index=>$sqlPattern) { $pattern=''; for ($i=0;$i<strlen($sqlPattern);$i++) { $c=$sqlPattern[$i]; $pattern.=$c.'.*'; } $this->sqlPatterns[$index]=str_replace('(','\(',$pattern); } parent::__construct($tagsArray, $attrArray, $tagsMethod, $attrMethod, $xssAuto); } function process($source, $get=false) { // clean all elements in this array foreach ($source as $key=>$values) { if (!is_array($values)) { $values=array($values); } foreach ($values as $value) { if (is_array($value)) { continue; } $value=urldecode($value); foreach ($this->sqlPatterns as $index=>$sqlPattern) { $found_sql=preg_match('#'.$sqlPattern.'#i',$value); if ($found_sql) { //Auto-block IP! if (class_exists('GProtector')) { $gprotector=new GProtector(); $ip=$gprotector->get_user_ip();; if ($ip<>'127.0.0.1') { if (!IS_LOCAL_HOST) { require_once (DIR_FS_CATALOG.'includes/classes/class.phpmailer.php'); require_once (DIR_FS_INC.'xtc_php_mail.inc.php'); } if ($get) { $source_parameter='GET'; } else { $source_parameter='POST'; } $two_eol=PHP_EOL.PHP_EOL; $mail_body= date('d.m.Y, H:i:s').$two_eol. "SQL-Injection-Versuch von IP: $ip (".gethostbyaddr($ip).")".$two_eol. "In $source_parameter-Paramter '$key=$value;'"; $gprotector_blacklist_file=DIR_FS_DOCUMENT_ROOT.'GProtector/ip_blacklist.txt'; if (is_file($gprotector_blacklist_file)) { $gprotector_blacklist_content=trim(file_get_contents($gprotector_blacklist_file)); $add_to_blacklist=strpos($gprotector_blacklist_content,$ip)===false; } else { $add_to_blacklist=true; $gprotector_blacklist_content=''; } if ($add_to_blacklist) { if ($gprotector_blacklist_content) { $gprotector_blacklist_content.=PHP_EOL; } file_put_contents($gprotector_blacklist_file,$gprotector_blacklist_content.$ip); $mail_body.=$two_eol."Die IP '$ip' wurde in der Datei '$gprotector_blacklist_file' blockiert."; $mail_body.=$two_eol."Um diese Blockierung aufzuheben, den IP-Eintrag für '$ip' in der Datei '$gprotector_blacklist_file' entfernen."; } if (!IS_LOCAL_HOST) { $email_address=EMAIL_BILLING_ADDRESS; $email_billing_name=EMAIL_BILLING_NAME; $gm_mail_status = xtc_php_mail(EMAIL_BILLING_ADDRESS, EMAIL_BILLING_NAME, $email_address, $email_billing_name, '', $email_address, $email_billing_name, '', '', 'SQL-Injection-Versuch!!!', $mail_body, $mail_body); } exit(); //Terminate processing } } unset($source[$key]); } } } } return parent::process($source,$get); }}