order = $order; $customer = new Customer($order->id_customer); $cart = new Cart($order->id_cart); $this->customer = $customer; $this->cart = $cart; } } public function setFraudScore() { if( !Validate::isLoadedObject($this->order) ) { throw new Exception("this->order is not an object"); return false; } $this->fraudAccount(); $this->fraudAdresses(); $this->fraudEmail(); $this->fraudConnexion(); $this->fraudCountData(); $this->fraudInvite(); $this->alreadyInFraud(); } public function getFraudScore() { return $this->fraud_score; } public function getFraudReport() { return $this->fraud_report; } /** * Tools fraud **/ private function fraudAccount() { $account_today = time() - strtotime($this->customer->date_add) < 86400; $time_warn = in_array(date('H'), array('23', '00', '01', '02', '03', '04', '05')); $lower_warn = (mb_strtolower($this->customer->firstname) === $this->customer->firstname) && (mb_strtolower($this->customer->lastname) === $this->customer->lastname); $name_warn = preg_match('/^(.*)(farid|rahmani|siphia|zitouni|moussa)(.*)$/i', $this->customer->lastname) || preg_match('/(\w)\1{2,}/', $this->customer->firstname) || preg_match('/(\w)\1{2,}/', $this->customer->lastname); $account_today? $this->fraud_report[] = 'Compte créé moins de 24h avant la commande (+50)': TRUE; $time_warn? $this->fraud_report[] = 'Commande de nuit (+20)': TRUE; $lower_warn? $this->fraud_report[] = 'Nom en minuscules (+20)': TRUE; $name_warn? $this->fraud_report[] = 'Nom fraudeur ou anormal (+100)': TRUE; $this->fraud_score = $account_today * 50 + $time_warn * 20 + $lower_warn * 20 + $name_warn * 100; } private function fraudAdresses() { $this->delivery_country = (int) Db::getInstance()->getValue(' SELECT `id_country` FROM `'._DB_PREFIX_.'address` WHERE `id_address` = '.(int) $this->cart->id_address_delivery.' '); $this->invoice_country = (int) Db::getInstance()->getValue(' SELECT `id_country` FROM `'._DB_PREFIX_.'address` WHERE `id_address` = '.(int) $this->cart->id_address_invoice.' '); // restriction or France, Espagne, Belgique $foreign_delivery = ($this->delivery_country != 8 && $this->delivery_country != 6 && $this->delivery_country != 3); $foreign_invoice = ($this->invoice_country != 8 && (int) $this->cart->id_address_invoice != (int) $this->cart->id_address_delivery) || ($this->invoice_country == 8 && $this->delivery_country != 8); $delivery_warn = (bool) Db::getInstance()->getValue(' SELECT `id_cart` FROM `'._DB_PREFIX_.'socolissimo_delivery_info` WHERE `id_cart` = '.(int) $this->cart->id.' AND `delivery_mode` != "DOM" '); $livraison_relai_idf = Db::getInstance()->getRow(' SELECT SUBSTRING(`przipcode`, 1, 2) as zipcode, `delivery_mode` FROM `'._DB_PREFIX_.'socolissimo_delivery_info` WHERE `id_cart` = '.(int) $this->cart->id.' AND `delivery_mode` != "DOM" '); $delivery_dpt_risk = FALSE; if(!empty($livraison_relai_idf)) { if($livraison_relai_idf['zipcode'] == 75 || $livraison_relai_idf['zipcode'] == 92 || $livraison_relai_idf['zipcode'] == 93) { $delivery_dpt_risk = TRUE; } } $delivery_dpt_risk ? $this->fraud_report[] = 'Livraison département à risque (75,92,93) (+30)': TRUE; $foreign_delivery? $this->fraud_report[] = 'Livraison à l\'étranger (+50)': TRUE; $foreign_invoice? $this->fraud_report[] = 'Facturation à l\'étranger (+50)': TRUE; $delivery_warn? $this->fraud_report[] = 'Livraison hors domicile (+20)': TRUE; $this->fraud_score += $foreign_delivery * 50 + $foreign_invoice * 50 + $delivery_warn * 20; } private function fraudEmail() { $freemail_warn = preg_match('/^(.*)@(yahoo|hotmail|gmail|yopmail|mail|mail2web|fastmail|mailinator|jetable|msn)\.(.*)$/i', $this->customer->email); $cctldmail_warn = preg_match('/^(.*)@(.*)\.(cn|cc|in|tw|ru|pl|ua|bg|bj|br|by|ci|dj|dz|eg|et|fj|hk|it|ma|si|tn|zw)$/i', $this->customer->email); $freemail_warn? $this->fraud_report[] = 'Utilisation d\'un compte mail ouvert (+20)': TRUE; $cctldmail_warn? $this->fraud_report[] = 'CCTLD de l\'email à risque (+100)': TRUE; $this->fraud_score += $freemail_warn * 20 + $cctldmail_warn * 100; } private function fraudConnexion() { $data = Db::getInstance()->getRow(' SELECT * FROM `ps_cart_fraud` WHERE `id_cart` = '. (int)$this->cart->id); if ($data) { $proxy = (bool)$data['proxy']; $ip_foreign = (bool)$data['ip_foreign']; $ip_alert = (bool)$data['ip_alert']; $freewifi = (bool)$data['freewifi']; $proxy? $this->fraud_report[] = 'Utilisation d\'un proxy (+20)': TRUE; $ip_foreign? $this->fraud_report[] = 'IP étrangère (+50)': TRUE; $ip_alert? $this->fraud_report[] = 'IP étrangère dans un pays en liste grise (+200)': TRUE; $freewifi? $this->fraud_report[] = 'Utilisation de Free Wifi (+50)': TRUE; $this->fraud_score += $proxy * 20 + $ip_foreign * 200 + $ip_alert * 50 + $freewifi * 50; } } private function fraudCountData() { $count_addresses = Db::getInstance()->getValue(' SELECT COUNT(*) FROM `'._DB_PREFIX_.'address` WHERE `id_customer` = '.(int) $this->customer->id.' AND `alias` NOT LIKE "So Colissimo %" '); if((int) $count_addresses > 2) { $this->fraud_score += 5 * ((int) $count_addresses - 2); $this->fraud_report[] = 'Compte à plus de 2 adresses (+'.(5 * ((int) $count_addresses - 2)).')'; } $count_orders = Db::getInstance()->getRow(' SELECT COUNT(*) AS `total` FROM `ps_orders` WHERE `id_customer` = '.(int) $this->customer->id.' AND `date_add` >= DATE_SUB(NOW(), INTERVAL 7 DAY) '); if($count_orders['total'] + 1 > 3) { $this->fraud_score += 100; $this->fraud_report[] = 'Compte origine de plus de 3 commandes ces 7 derniers jours (+100)'; } $count_products = Db::getInstance()->getRow(' SELECT COUNT(*) AS `total` FROM `ps_cart_product` WHERE `id_cart` = '.(int) $this->cart->id.' '); $count_total_paid = $this->cart->getOrderTotal(); if($count_products['total'] > 7 && $count_total_paid > 250) { $this->fraud_score += 100; $this->fraud_report[] = 'Plus de 7 produits dans le panier et total de plus de 250€ (+100)'; } $count_oldorders = Db::getInstance()->getValue(' SELECT COUNT(*) FROM `'._DB_PREFIX_.'orders` WHERE `id_customer` = '.(int) $this->customer->id.' AND `valid` = 1 AND `date_add` < DATE_SUB(NOW(), INTERVAL 30 DAY) '); if($count_oldorders > 3) { $this->fraud_score -= 50; $this->fraud_report[] = 'Compte avec plus de 3 commandes valides de plus de 30 jours (-50)'; } } private function fraudInvite() { $has_order = (bool) (int) Db::getInstance()->getValue(' SELECT `id_order` FROM `'._DB_PREFIX_.'orders` WHERE `id_customer` = '.(int) $this->customer->id.' AND `valid` = 1 '); $has_invite = (bool) (int) Db::getInstance()->getValue(' SELECT `id_invite` FROM `'._DB_PREFIX_.'invite` WHERE `id_customer` = '.(int) $this->customer->id.' '); $has_landingpage = (bool) (int) Db::getInstance()->getValue(' SELECT `id_landing_page` FROM `'._DB_PREFIX_.'landing_page_customer` WHERE `id_customer` = '.(int) $this->customer->id.' '); $has_invite ? ($has_landingpage ? $this->fraud_report[] = 'En provenance d\'une landing page avec parrain (-100)' : ((strtotime($this->customer->date_add) < time() - 7776000) && $has_order ? $this->fraud_report[] = 'Parrain et compte de plus de 3 mois avec commande (-100)' : TRUE ) ) : TRUE ; $this->fraud_score += ($has_invite ? ($has_landingpage || ((strtotime($this->customer->date_add) < time() - 7776000) && $has_order) ? -100 : 0 ) : 0 ); } public function alreadyInFraud() { $already_fraud = Db::getInstance()->getValue(' SELECT COUNT(h.`id_order`) FROM `'._DB_PREFIX_.'order_history` h LEFT JOIN `'._DB_PREFIX_.'orders` o on h.`id_order` = o.`id_order` WHERE o.`id_customer` = '.(int) $this->customer->id.' AND h.`id_order_state` IN (15,16,18) '); $already_suspect = Db::getInstance()->getValue(' SELECT COUNT(rep.`id_cart`) FROM `'._DB_PREFIX_.'order_reputation` rep LEFT JOIN `'._DB_PREFIX_.'cart` c ON c.`id_cart` = rep.`id_cart` WHERE c.`id_customer` = '.(int) $this->customer->id.' AND rep.`score` > 100 '); if ($already_suspect || $already_fraud) { $this->fraud_score += 200; $this->fraud_report[] = 'Compte avec des commandes en suspicion de fraude, fraude non détectée ou commandes frauduleuses (+200)'; } // Adding from 23/02/2016 $already_suspect_by_names = Db::getInstance()->getValue(' SELECT COUNT(rep.`id_cart`) FROM `'._DB_PREFIX_.'order_reputation` rep LEFT JOIN `'._DB_PREFIX_.'cart` c ON c.`id_cart` = rep.`id_cart` LEFT JOIN `'._DB_PREFIX_.'customer` cu ON cu.`id_customer` = c.`id_customer` WHERE cu.`firstname` = "'.pSQL($this->customer->firstname).'" AND cu.`lastname` = "'.pSQL($this->customer->lastname).'" AND c.`id_customer`!='.$this->customer->id.' AND rep.`score` > 100 '); $already_fraud_by_names = Db::getInstance()->getValue(' SELECT COUNT(h.`id_order`) FROM `'._DB_PREFIX_.'order_history` h LEFT JOIN `'._DB_PREFIX_.'orders` o on h.`id_order` = o.`id_order` LEFT JOIN `'._DB_PREFIX_.'customer` cu ON cu.`id_customer` = o.`id_customer` WHERE cu.`firstname` = "'.pSQL($this->customer->firstname).'" AND cu.`lastname` = "'.pSQL($this->customer->lastname).'" AND o.`id_customer`!='.(int) $this->customer->id.' AND h.`id_order_state` IN (15,16,18) '); if ($already_suspect_by_names || $already_fraud_by_names) { $this->fraud_score += 200; $this->fraud_report[] = 'Existance d\'autres comptes de mêmes noms avec des commandes en suspicion de fraude, fraude non détectée ou commandes frauduleuses (+200)'; } } public static function getReputationOrder($id_order) { $id_cart = Order::getCartIdStatic($id_order); return Db::getInstance()->getRow(' SELECT * FROM `'._DB_PREFIX_.'order_reputation` WHERE `id_cart` = '. (int)$id_cart ); } public static function validOrder($id_order) { $id_cart = Order::getCartIdStatic($id_order); $order = new Order($id_order); $sql = 'UPDATE `'._DB_PREFIX_.'order_reputation` SET pass = 1 WHERE id_cart = '. (int)$id_cart; if (Db::getInstance()->execute($sql)) { Db::getInstance()->execute(' UPDATE `'._DB_PREFIX_.'reputation` SET `score` = 0 WHERE `id_customer` = '.(int)$order->id_customer ); Db::getInstance()->execute(' DELETE FROM `'._DB_PREFIX_.'order_history` WHERE `id_order` = '. (int)$id_order .' AND `id_order_state` = 18' ); return TRUE; } else { return FALSE; } } public static function cidr_match($ip, $range) { list ($subnet, $bits) = explode('/', $range); $ip = ip2long($ip); $subnet = ip2long($subnet); $mask = -1 << (32 - $bits); $subnet &= $mask; return ($ip & $mask) == $subnet; } public static function CartFraudConnexion(Cart $cart) { if (!Validate::isLoadedObject($cart)) { return false; } $proxy_warn = FALSE; foreach(array( 'HTTP_VIA', 'HTTP_X_FORWARDED_FOR', 'HTTP_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_FORWARDED', 'HTTP_CLIENT_IP', 'HTTP_FORWARDED_FOR_IP', 'VIA', 'X_FORWARDED_FOR', 'FORWARDED_FOR', 'X_FORWARDED', 'FORWARDED', 'CLIENT_IP', 'FORWARDED_FOR_IP', 'HTTP_PROXY_CONNECTION', ) as $x){ if(isset($_SERVER[$x])) { $proxy_warn = TRUE; break; } } if(self::cidr_match(Tools::getRemoteAddr(), '78.250.0.0/15')) { $freewifi = TRUE; } else { $freewifi = FALSE; } include_once(_PS_GEOIP_DIR_.'geoipcity.inc'); include_once(_PS_GEOIP_DIR_.'geoipregionvars.php'); $gi = geoip_open(realpath(_PS_GEOIP_DIR_.'GeoLiteCity.dat'), GEOIP_STANDARD); $record = geoip_record_by_addr($gi, Tools::getRemoteAddr()); $delivery_country = new Address($cart->id_address_delivery); if($delivery_country InstanceOf Address) { $foreignip_warn = is_object($record) ? ( $record->country_code == 'FR' ? FALSE : ( strtolower($record->country_code) == Db::getInstance()->getValue(' SELECT LOWER(`iso_code`) FROM `'._DB_PREFIX_.'country` WHERE `id_country` = '.(int) $delivery_country->id_country.' ') ? FALSE : TRUE ) ) : FALSE; // error_log('BBB - IP ETRANGERE'); } else{ $foreignip_warn = false; } $foreignip_alert = is_object($record) ? ( in_array($record->country_code, array( 'DE', 'AD', 'AT', 'BE', 'BG', 'CA', 'DK', 'ES', 'US', 'FI', 'FR', 'GI', 'GR', 'GP', 'GY', 'GF', 'HU', 'IE', 'IT', 'RE', 'LU', 'MQ', 'MC', 'NC', 'NL', 'PL', 'PT', 'CZ', 'GB', 'UK', 'SM', 'MF', 'SX', 'CH', 'TD', 'TF', 'VA', 'WF', )) ? FALSE : TRUE ) : FALSE; Db::getInstance()->ExecuteS(' INSERT INTO `'._DB_PREFIX_.'cart_fraud` VALUES ( '.(int)$cart->id.', '.(int)$proxy_warn.', '.(int)$foreignip_alert.', '.(int)$foreignip_warn.', '.(int)$freewifi.', "'.Tools::getRemoteAddr().'" ) ON DUPLICATE KEY UPDATE `proxy` = '.(int)$proxy_warn.', `ip_foreign` = '.(int)$foreignip_alert.', `ip_alert` = '.(int)$foreignip_warn.', `freewifi` = '.(int)$freewifi.', `ip_cart` = "'.Tools::getRemoteAddr().'" '); } }