Перейти к содержанию
artnazarov

Слой защиты общего назначения для OpenCart

Рекомендуемые сообщения

Взлом сайта начинается с внедрения в запросы вредоносных управляющих строк, позволяющих в зависимости от цели атакующего реализовать такие сценарии как установка паразитного управляющего модуля (шелл), уничтожение базы данных, получение доступа к конфиденциальным сведениям, скрытое размещение рекламы, отрицательно влияющее на позиции в поисковике, получение доступов к серверу и т.п.

Не секрет, что для осуществления этих атак все чаще используется специальный софт, позволяющий просканировать сайт на уязвимости и даже выполнить их эксплуатацию по заранее подготовленным сценариям. Все чаще атаки на коммерческие сайты приобретают массовый характер и затрагивают тысячи ресурсов по всему миру. 

К сожалению, не все уязвимости обнаруживаются и закрываются основной командой в самом динамично развивающемся движке, не говоря уже о модулях, подготовленных участниками коммьюнити.

 

Следовательно, для защиты интернет-магазинов на OpenCart необходимо разбирать фрагменты запросов от пользователей еще до того, как они попадут в любые компоненты системы, поскольку человеческий фактор в безопасности - один из решающих.

Советы: Для защиты сайта можно прикрыть сервер с помощью сервисов вроде CLOUDFLARE, QRATOR, VIRUSDIE и т.п Выполняйте сканирование файловой системы сайта с помощью бесплатного антивируса Манул, других скриптов и утилит, имеющих возможности отслеживать появление новых неизвестных файлов и изменения в файлах существующих.

Это позволит вовремя заметить факт взлома.

Но что делать, если в Вашем бюджете пока не предусмотрен Qrator, VirusDie или Cloudflare? Что делать, если у Вас нет ресурсов устраивать тщательный аудит кода на безопасность для каждого из модулей, которые Вы устанавливаете?  Утилиты вроде Acunetix имеют дорогие лицензии, а ими надо еще научиться пользоваться.

А безопасностью заниматься в наше непростое время надо как никогда.

 

Подобно тому, как операционные системы имеют несколько колец или слоев защиты, так и OpenCart нуждается в создании такого слоя, хотя бы в минимальном объеме  защищающем от исполнения XSS и SQL инъекций. Эффективность разработки такого слоя может быть достигнута только при предположении, что движок и модули имеют незакрытые уязвимости.

Этот слой должен быть размещен между ядром системы и контроллерами и запросами.

 

Таким образом, идея состоит в том, что нельзя доверять ни сайту (может быть заражен или уязвим), ни запросам (могут быть вредоносными). Нельзя доверять разработчикам модулей, поскольку они концентрируют свои усилия на выполнении определенных задач и могут просто не заметить проблем с безопасностью своего кода.

 

Сам же слой должен быть настолько прост и лаконичен, насколько это вообще возможно, чтобы  его собственная безвредность, соответствие требованиям и безопасность была очевидна. Он не должен опираться на остальные инструменты CMS и быть переносимым между разными CMS - CMS меняются, а безопасность остается.

 

Как мог бы выглядеть подобный слой:

 

Практический пример:

Сохраняем в корне сайта файл protection.php.

<?php
// АРТЁМ
// admin@artnazarov.ru, подойдет для любых CMS на PHP
define('PROTECTION', true);
// change this setting to your one
define('MAIN_PAGE_URL', '/');

function request_handle($filter)
{
$rq = $_SERVER['REQUEST_URI'];
if (true == isset($_SESSION['hits']))
{
$_SESSION['hits'] = $_SESSION['hits'] + 1;
$mt = microtime(true);
$lasthit = ($mt-$_SESSION['lasthit']);
$_SESSION['lasthit'] = $mt;
$hits = $_SESSION['hits'];
}
else
{
$_SESSION['hits'] = 1;    
$hits = 1;
$_SESSION['lasthit'] = microtime(true);
$lasthit = 999;
};
$lasthit = $lasthit*1000;
$timeout = 15;
if ($filter)
{
    

if (($lasthit<=750) && ($rq!=MAIN_PAGE_URL))
        {            
            echo "<html><head>
            <meta http-equiv='refresh' content='$timeout;$rq'>
            <title>Система защиты</title><meta charset='utf-8'><body>
    <b>Система защиты.</b> 
    <p>Между повторными запросами прошло менее $lasthit мс! Вы будете автоматически перенаправлены на запрошенную страницу
    через $timeout сек.</p>    
    </body></html>";
            exit;
            die();

            };
            
};            
return $hits;        
}

function statinfo($hits)
{    
$v_ip = $_SERVER['REMOTE_ADDR'];
$ag = $_SERVER['HTTP_USER_AGENT'];
$ru = $_SERVER['REQUEST_URI'];
$v_date = date("l d F H:i:s"); 
$fp = fopen("./logs/ips.log", "a+");
fputs($fp, "IP:$v_ip;REQUEST:$ru;DATE:$v_date;USERAGENT:$ag;HITS:$hits#\n\r\n\r");
fclose($fp);
}

/* GENERAL PROTECTION LAYER */

function dang_symb($str)
{
 $test = false;
  // check fragments of php/js code  
 if (strpos($str, "base64")!==false) {$test = true;};
 if (strpos($str, 'eval')!==false) {$test = true;};
 if (strpos($str, 'write')!==false) {$test = true;};
  //  check specials chars and delimeters
 if (strpos($str, "\\")!==false) {$test = true;};
 if (strpos($str, '0x')!==false) {$test = true;};
 if (strpos($str, '/*')!==false) {$test = true;};
 if (strpos($str, '*/')!==false) {$test = true;};
 if (strpos($str, '|')!==false) {$test = true;};
 if (strpos($str, '&&')!==false) {$test = true;};
 if (strpos($str, '--')!==false) {$test = true;};
 if (strpos($str, ':;')!==false) {$test = true;};
 if (strpos($str, ';')!==false) {$test = true;};
 if (strpos($str, '*')!==false) {$test = true;};
 if (strpos($str, ':=')!==false) {$test = true;}; 
 if (strpos($str, '(')!==false) {$test = true;}; 
 if (strpos($str, ')')!==false) {$test = true;}; 
 if (strpos($str, "'")!==false) {$test = true;}; 
 if (strpos($str, ",")!==false) {$test = true;}; 
 if (strpos($str, "#")!==false) {$test = true;}; 
 if (strpos($str, "$")!==false) {$test = true;}; 
 if (strpos($str, "|")!==false) {$test = true;}; 
 if (strpos($str, "<")!==false) {$test = true;}; 
 if (strpos($str, ">")!==false) {$test = true;}; 
 if (strpos($str, "[")!==false) {$test = true;}; 
 if (strpos($str, "]")!==false) {$test = true;}; 
 if (strpos($str, "~")!==false) {$test = true;}; 
 if (strpos($str, "`")!==false) {$test = true;}; 
   // detect calls to OS tools
   // for WIN
 if (strpos($str, "..")!==false) {$test = true;}; 
 if (strpos($str, "/etc/passwd")!==false) {$test = true;}; 
 if (strpos($str, "c:\\")!==false) {$test = true;}; 
 if (strpos($str, "cmd.exe")!==false) {$test = true;}; 
 if (strpos($str, "\\")!==false) {$test = true;}; 
 if (strpos($str, "//")!==false) {$test = true;}; 
 if (strpos($str, "`")!==false) {$test = true;}; 
   // for NIX   
 if (strpos($str, "yum")!==false) {$test = true;}; 
 if (strpos($str, "apt")!==false) {$test = true;}; 
 if (strpos($str, "sudo")!==false) {$test = true;}; 
 if (strpos($str, "rm")!==false) {$test = true;}; 
    // check that no one parts of request have a SQL operators
  if (strpos(strtoupper($str), 'UNION')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'SELECT')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'DROP')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'GROUP')!==false) {$test=true;};  
  if (strpos(strtoupper($str), 'WHERE')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'UPDATE')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'COUNT')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'HAVING')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'SCRIPT')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'DELETE')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'OR ')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'AND ')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'IN ')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'SCRIPT')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'INSERT')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'INTO ')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'VALUES')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'TABLE')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'GRANT')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'ROLLBACK')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'COMMIT')!==false) {$test=true;};
  if (strpos(strtoupper($str), 'CREATE')!==false) {$test=true;};
  
 return $test;
 }
 
function dang_in_arr($arr)
{
 $test_g = false;
 foreach ($arr as $k => $v)
 {
	if (dang_symb($v)===true) {$test_g = true;};
 };
 return $test_g;
}

function test_get()
{
 return dang_in_arr($_GET);
}

function test_post()
{
 return dang_in_arr($_POST);
}
       
function test_session()
{
 return dang_in_arr($_SESSION);
}
       
function test_server()
{
 return dang_in_arr($_SERVER);
}
       
 function test_cookie()
{
 return dang_in_arr($_COOKIE);
}



function test_both()
{
	return (test_get() || test_post() || test_server() || test_session() || test_cookie() );
}

function die_on_dang()
{
	if (test_both()===true) die('Malware symbols detected');
  // here may be code to ban this IP on some time
}

function general_protection($filter = true)
{
  if (PROTECTION)
  {
  // dont process hits with high frequency 
  $hits = request_handle($filter);
  statinfo($hits); // log to journal
  if ($filter)
  {
    die_on_dang(); // stop any activity on danger
  };
  };
}

?>

 

в файлах /index.php и /admin/index.php перед всеми инструкциями ставим первыми вызов защитной прослойки

require_once($_SERVER['DOCUMENT_ROOT'] . '/protection.php');
general_protection();

 

Результат: теперь попытки отправить нам на сайт в запросе прелести вроде eval, script или drop database и т.п. будут пресекаться на корню. Он универсален и подойдет для любой CMS.

 

Код опубликован "как есть", без каких-либо гарантий с моей стороны. 

Буду рад конструктивным предложениям по улучшению этого фильтра.

 

Если у Вас есть наработки и идеи по такого рода защите, если Вам что-либо известно об аналогичных модулях (возможно, в рамках других CMS), пожалуйста напишите об этом в этой теме или отправьте мне свои соображения на почту admin@artnazarov.ru.

 

Уверен, что всем в той или иной степени интересна тема повышения безопасности OpenCart.

 

Пишу здесь, поскольку не уверен, что кто-либо из core/kernel team будет это когда-либо имплементировать, рефакторить или развивать, с учетом своеобразного характера персонажей вроде Daniel Kerr

 

Желаю всем растущих продаж, отличной конверсии и 100% аптайма :-)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Подписался :) Чую рождается новый мем.

 

ЗЫ: А ежели аффтор через год другой узнает о существовании регулярных выражений...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

спорные рекомендации по поводу

 

  //  check specials chars and delimeters

 

 if (strpos($str, "..")!==false) {$test = true;}; - хм... прикольно - хотелось бы знать причину...  (что такое  ..  я знаю)

 

if (strpos($str, "`")!==false) {$test = true;}; - дважды

 

и... уже есть модуль для этого

 

И... есть более универсальный способ подключения такого файла,  который пропустит через себя все запросы, в том числе и к сторонним скриптам.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проверка на якобы SQL инъекцию бессмысленна

 

Я могу передавать текст, содержащий что-то из этого набора. кроме того, если заметите,  то select  insert update -  слова часто встречающиеся и в русскоязычных текстах,а  также может быть т в аякс запросах

 

У меня есть провайдер, который фильтрует  =1, ссылаясь на то что это общеизвестные фильтры, и отключать не хочет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

этож просто GENERAL PROTECTION LAYER не судите его строго. Не генеральское это дело вникать в специфику.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

"Проверка на SQL инъекцию бессмысленна".

Охранники в банке не нужны? Патрули в общественных местах?

 

1. А regex медленнее, чем strpos. 

2. Загнать в массив параметры было бы медленнее и прогнать в цикле тоже было бы медленно.

3. Возможные проблемы c REQUEST_URI и т.п. понятны, но разрешимы.
Однако, UPDATE в search запросах звучало бы странно :)

 

Рад, что к сообщению гуру, снизошедшие до простого смертного, относятся с юмором, пытаются

что-то осмысленное написать, медитируют над кодом, выискивая что-то, что позволило бы им почувствовать

себя крутышами.  Самовлюбленность меж тем противоречит общему делу.

 

Что ж, возможно, кто-то из гуру отважится аналог Manul для OpenCart написать.

Но что-то не наблюдаю что-то в магазине дополнений таких решений.

А они не одного меня, убогого, интересуют. Вы бы свой код показали.

Я ж не стесняюсь. Модули по безопасности пользовались бы большим спросом.

 

Все беды именно от уверенности в защищенности,  и в том, что всегда найдется крайний.

В мире бандерлогов-ревьюеров и розовых пони, блюющих радугой, все безоблачно )

 

Ведь есть Kerr со товарищи,  спасет quoting и т.п.  Поэтому и response и request считают безопасными,

под капотом же все все в порядке :) Ничего не произойдет. Ничего...

 

А дыры-то на текущих релизах должны быть в безопасности и не факт, что новых, не озвученных публично, не появится в новых версиях. Тех, о которых владельцы узнают только тогда, когда произойдет взлом. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

этож просто GENERAL PROTECTION LAYER не судите его строго. Не генеральское это дело вникать в специфику.

 

Не вникай.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

спорные рекомендации по поводу

 

  //  check specials chars and delimeters

 

 if (strpos($str, "..")!==false) {$test = true;}; - хм... прикольно - хотелось бы знать причину...  (что такое  ..  я знаю)

 

if (strpos($str, "`")!==false) {$test = true;}; - дважды

 

и... уже есть модуль для этого

 

И... есть более универсальный способ подключения такого файла,  который пропустит через себя все запросы, в том числе и к сторонним скриптам.

 

О каком модуле речь, о каком способе подключения вы говорите.

Был бы премного благодарен за ответ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Подписался :) Чую рождается новый мем.

 

ЗЫ: А ежели аффтор через год другой узнает о существовании регулярных выражений...

 

Действительно, лучше всего это работает после применения патча Бармина. 

Попробуйте именно в таком порядке у себя на сервере.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

Рад, что к сообщению гуру, снизошедшие до простого смертного, относятся с юмором, пытаются

что-то осмысленное написать, медитируют над кодом, выискивая что-то, что позволило бы им почувствовать

себя крутышами.  Самовлюбленность меж тем противоречит общему делу.

Советую сбавить обороты в поисках всевдосатирических фраз.

 

Ни на один мой вопрос не отвечено.

 

И, я так понимаю, что вы не удосужились поиском модуля, а тем более способа подключения своих скриптов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проверка на якобы SQL инъекцию бессмысленна

 

Я могу передавать текст, содержащий что-то из этого набора. кроме того, если заметите,  то select  insert update -  слова часто встречающиеся и в русскоязычных текстах,а  также может быть т в аякс запросах

 

У меня есть провайдер, который фильтрует  =1, ссылаясь на то что это общеизвестные фильтры, и отключать не хочет.

Полностью поддерживаю chukcha - за четыре года работы с opencart и более 500 ИМ,  ни разу не видел взлома через описанные в топике костыли, зато избыточных вычислений ...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

suhosin, не?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

×

Важная информация

На нашем сайте используются файлы cookie и происходит обработка некоторых персональных данных пользователей, чтобы улучшить пользовательский интерфейс. Чтобы узнать для чего и какие персональные данные мы обрабатываем перейдите по ссылке. Если Вы нажмете «Я даю согласие», это означает, что Вы понимаете и принимаете все условия, указанные в этом Уведомлении о Конфиденциальности.