Форум русскоязычного сообщества Ubuntu


Увидели сообщение с непонятной ссылкой, спам, непристойность или оскорбление?
Воспользуйтесь ссылкой «Сообщить модератору» рядом с сообщением!

Автор Тема: Защита от DoS глазами новичка - nginx  (Прочитано 1054 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн anomal3

  • Автор темы
  • Новичок
  • *
  • Сообщений: 34
    • Просмотр профиля
Небольшое отступление!
Форум очень большой. Не смог найти подходящего раздела, поэтому прошу модераторов отнестись с пониманием и в случае чего перенести тему в соответствующий раздел.
Поехали...
Больше полу года назад, работая в проектной компании, мы решили обзавестись собственным файлообменником с заказчиками. Почитав мануалы и статьи, я пришёл к выводу что будет логично развернуть собственное облако на Linux системе а именно Ubuntu 16.04.3LTS.
За основу я взял знаменитый ownCloud. Развернуть облако не составило никакого труда, всё легло как по маслу.
И наше облако начали активно использовать заказчики похлопывая в ладоши, и говоря как же это удобно.

Развернул я облако на связке Apache + PHP7.0 + MySQL. С этими "демонами" я уже встречался ранее, но как новичок, не имея плотного знакомства мне хватало справляться с поставленными задачами, да и плюс в интернете полным полно мануалов. Я говорю про (пример) изменение портов, подключение HTTPS, и т.п.

Но месяца 1,5 назад, с нашим облаком да и вообще с сетью, началась твориться магия. Облако периодически начало подвисать, то доступно то нет, сеть интернет тоже начала шалить. Первым делом я конечно же связался с провайдером, кто нас кормит интернетом. После многочисленных проверок мне сказали, мол все у вас в порядке, дело не в линии, а в вашем оборудовании. Ну ладно, пробуем методом исключений. Перезагружаем роутер, и о чудо, интернет появляется минут на 5 и снова такая вакханалия. Значит дело в другом. Посмотрев конфиги апача, ведь именно он отвечает за наше облако, я увидел что добавились какие то дополнительные конфиги. Я начал гуглить информацию, и как оказалось Apache обновился до версии 2.4.18 (видимо apt update сделал своё дело). Почитал как посмотреть ошибки
apache2 -t
и как их пофиксить. Вроде сделал, но проблема не ушла, а значит дело не в Апаче. Долго изучая конфиги, и читая статьи, понял что решать данную проблему придется изучая логи, лоооги, лоо-о-о-оги, о боже, только не их. Я в них нефига не понимаю и их так много. Но делать было нечего. Сел за изучение логов, пытаясь дойти до чего-нибудь логичного своим мозгом. Ну Вы представьте, за пол года читать логи, УЖАС!.

Но спустя N-ное количество времени я заметил подозрительную активность
[Mon Jun 18 21:25:29.021638 2018] [mpm_prefork:notice] [pid 3593] AH00163: Apache/2.4.18 (Ubuntu) configured -- resuming normal operations
[Mon Jun 18 21:25:29.021722 2018] [core:notice] [pid 3593] AH00094: Command line: '/usr/sbin/apache2'
[Mon Jun 18 21:41:24.850827 2018] [mpm_prefork:notice] [pid 3593] AH00169: caught SIGTERM, shutting down
[Mon Jun 18 21:41:26.033616 2018] [mpm_prefork:notice] [pid 6733] AH00163: Apache/2.4.18 (Ubuntu) configured -- resuming normal operations
[Mon Jun 18 21:41:26.033694 2018] [core:notice] [pid 6733] AH00094: Command line: '/usr/sbin/apache2'
[Mon Jun 18 21:43:17.328967 2018] [mpm_prefork:notice] [pid 6733] AH00169: caught SIGTERM, shutting down
[Mon Jun 18 21:43:18.443306 2018] [mpm_prefork:notice] [pid 7172] AH00163: Apache/2.4.18 (Ubuntu) configured -- resuming normal operations
[Mon Jun 18 21:43:18.443383 2018] [core:notice] [pid 7172] AH00094: Command line: '/usr/sbin/apache2'
[Mon Jun 18 23:05:33.572588 2018] [:error] [pid 9356] [client 203.195.132.58:1905] script '/var/www/html/wuwu11.php' not found or unable to stat
[Mon Jun 18 23:05:34.055989 2018] [:error] [pid 9399] [client 203.195.132.58:1984] script '/var/www/html/xw.php' not found or unable to stat
[Mon Jun 18 23:05:34.570828 2018] [:error] [pid 9385] [client 203.195.132.58:2064] script '/var/www/html/xx.php' not found or unable to stat
[Mon Jun 18 23:05:35.084697 2018] [:error] [pid 8945] [client 203.195.132.58:2104] script '/var/www/html/s.php' not found or unable to stat
[Mon Jun 18 23:05:35.581628 2018] [:error] [pid 8863] [client 203.195.132.58:2210] script '/var/www/html/w.php' not found or unable to stat
[Mon Jun 18 23:05:36.048029 2018] [:error] [pid 9355] [client 203.195.132.58:2278] script '/var/www/html/db.init.php' not found or unable to stat
[Mon Jun 18 23:05:36.549565 2018] [:error] [pid 8856] [client 203.195.132.58:2452] script '/var/www/html/db_session.init.php' not found or unable to stat
[Mon Jun 18 23:05:37.046265 2018] [:error] [pid 9358] [client 203.195.132.58:2519] script '/var/www/html/sheep.php' not found or unable to stat
[Mon Jun 18 23:05:37.582546 2018] [:error] [pid 9354] [client 203.195.132.58:2629] script '/var/www/html/index.php' not found or unable to stat
[Mon Jun 18 23:05:43.230844 2018] [:error] [pid 9354] [client 203.195.132.58:2629] script '/var/www/html/mysql/index.php' not found or unable to stat
[Tue Jun 19 06:37:17.184153 2018] [:error] [pid 9400] [client 116.204.103.129:25543] script '/var/www/html/mysql/index.php' not found or unable to stat
[Tue Jun 19 11:44:15.078641 2018] [:error] [pid 8856] [client 223.105.4.250:17113] script '/var/www/html/index.php' not found or unable to stat

Вот так вот брут ищет уязвимости.
Запросил информацию по ip и удивился, ЧАЙНА.

Но так как я раньше не сталкивался с таким чудом, я создал тему на форуме, и спросил что это за активность.
Знающие гуру (СПАСИБО им больше) подтвердили мои догадки, это была DDOS АТАКА.
Дос атакой нас грузили на протяжении 1,5 месяца, заказчики нервничали, и начальство тоже, а моя пятная точка горела всё больше и больше.

Опять изучение статей. Разные попытки заглушить атаку не увенчались успехом.
Я пробовал на главной странице index.php методом геопризнака, переадресовывать клиентов не из России в попенгаген.
Страница index.php
Код: (php) [Выделить]
<?php
 
include("country.php");
 
$ip $_SERVER['REMOTE_ADDR'];
 
$geopoloj strana($ip);
 switch (
$geopoloj) {
  case 
"UA":
 
$goLoc "http://попенгаген.рф/redirect/ua.html";
 break;
  case 
"EU":
 
$goLoc ="http://попенгаген.рф/redirect/eu.html";
 break;
  case 
"FR":
 
$goLoc "http://попенгаген.рф/redirect/fr.html";
 break;
 case 
"DE":
 
$goLoc "http://попенгаген.рф/redirect/de.html";
 break;
 case 
"CN":
 
$goLoc "http://попенгаген.рф/redirect/cn.html";
 break;
  case 
"RU":
 
$goLoc "index-verify.html";
 break;
   case 
"US":
 
$goLoc "http://попенгаген.рф/redirect/eu.html";
 break;
  default:
 
$goLoc "http://попенгаген.рф/redirect/eu.html";
 }
 
header("location: $goLoc");
?>

А вот Инклуднутый country.php
Код: (php) [Выделить]
<?php
 
function strana($ip){
    
$fh fopen(dirname(__FILE__) . DIRECTORY_SEPARATOR 'tabgeo_country_v4.dat''rb');
    
$iso = array('AD''AE''AF''AG''AI''AL''AM''AO''AQ''AR''AS''AT''AU''AW''AX''AZ',
            
'BA''BB''BD''BE''BF''BG''BH''BI''BJ''BL''BM''BN''BO''BQ''BR''BS',
            
'BT''BV''BW''BY''BZ''CA''CC''CD''CF''CG''CH''CI''CK''CL''CM''CN',
            
'CO''CR''CU''CV''CW''CX''CY''CZ''DE''DJ''DK''DM''DO''DZ''EC''EE',
            
'EG''EH''ER''ES''ET''FI''FJ''FK''FM''FO''FR''GA''GB''GD''GE''GF',
            
'GG''GH''GI''GL''GM''GN''GP''GQ''GR''GS''GT''GU''GW''GY''HK''HM',
            
'HN''HR''HT''HU''ID''IE''IL''IM''IN''IO''IQ''IR''IS''IT''JE''JM',
            
'JO''JP''KE''KG''KH''KI''KM''KN''KP''KR''KW''KY''KZ''LA''LB''LC',
            
'LI''LK''LR''LS''LT''LU''LV''LY''MA''MC''MD''ME''MF''MG''MH''MK',
            
'ML''MM''MN''MO''MP''MQ''MR''MS''MT''MU''MV''MW''MX''MY''MZ''NA',
            
'NC''NE''NF''NG''NI''NL''NO''NP''NR''NU''NZ''OM''PA''PE''PF''PG',
            
'PH''PK''PL''PM''PN''PR''PS''PT''PW''PY''QA''RE''RO''RS''RU''RW',
            
'SA''SB''SC''SD''SE''SG''SH''SI''SJ''SK''SL''SM''SN''SO''SR''SS',
            
'ST''SV''SX''SY''SZ''TC''TD''TF''TG''TH''TJ''TK''TL''TM''TN''TO',
            
'TR''TT''TV''TW''TZ''UA''UG''UM''US''UY''UZ''VA''VC''VE''VG''VI',
            
'VN''VU''WF''WS''YE''YT''ZA''ZM''ZW''XA''YU''CS''AN''AA''EU''AP',
    );
    
$tabgeo_bs = function($data_array$ip$step){
        
$start 0;
        
$end   count($data_array) - 1;
        while (
true) {
            
$mid    floor(($start $end) / 2);
            
$unpack $step unpack('Noffset/Cip/Ccc_id'"\x00$data_array[$mid]") : unpack('Cip/Ccc_id'$data_array[$mid]);
            if (
$unpack['ip'] == $ip) return $unpack;
            if (
$end $start  <   0) return $ip $unpack['ip'] ? $unpack $unpack_prev;
            if (
$unpack['ip']  > $ip$end $mid 1; else $start $mid 1;
            
$unpack_prev $unpack;
        }
    };
 
    
$ip_array explode('.'$ip);
    
fseek($fh, ($ip_array[0] * 256 $ip_array[1]) * 4);
    
$index_bin fread($fh4);
    
$index unpack('Noffset/Clength'"\x00$index_bin");
    if(
$index['offset'] == 16777215) return $iso[$index['length']];
    
fseek($fh$index['offset'] * 262144);
    
$bin fread($fh, ($index['length'] + 1) * 5);
    
$d $tabgeo_bs(str_split($bin5), $ip_array[2], TRUE);
    if(
$d['offset'] == 16777215) return $iso[$d['cc_id']];
    if(
$ip_array[2] > $d['ip']) $ip_array[3] = 255;
    
fseek($fh, -(($d['offset'] + $d['cc_id']) * 2), SEEK_END);
    
$bin fread($fh, ($d['cc_id'] + 1) * 2);
    
$d $tabgeo_bs(str_split($bin2), $ip_array[3], FALSE);
    return 
$iso[$d['cc_id']];
}

Но это поять же не помогло.

После долгих изучений, казался только один выход, поставить поверх Апача Nginx. Но вот только мозгов моих на это не хватит. Я новичок в этом.

Но мне попалась хорошая статься сравнений этих демонов
https://habr.com/post/267721/

И было принято решение полностью отказаться от apache.
Сделав резервную копию базы и сайта /var/www/html
Я поставил систему с нуля, и запустил на нём Nginx. Так же подключил php и mysql.
И тут началось самое интересное. Настройки

Часть 2...
После того как Nginx запущен и сделаны первоначальные настройки(они расписаны в любой статье), он никак не может распознать php.
В интернете полно статей о том как настроить конфиг.

location ~ \.php$ {
try_files $uri =404;
include /etc/nginx/fastcgi.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;

}


Данный код подключает php, но в следствии за ним ещё куча настроек, таких как время ожидания, Максимальный размер файла и прочих. Благо на ownCloud есть уже готовый пример, правда пришлось немного его править.
В итоге получил полностью рабочий конфиг который хранится в /etc/nginx/sites-avalible/default
(Нажмите, чтобы показать/скрыть)

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

Ну раз я уже начитан, и знаю что дальше делать, я принялся менять конфиги и защищать себя от доса по геопризнаку.
Мне известно, что все наши клиенты из России, так же по логам я видел, что злоумышленник не просто караулит меня, а делает это с изыском. С помощью API сайта https://proxycheck.io/ гореть им в аду за это, я понимал, что клиентам из других стран нечего делать в нашем облаке.

А посему было принято решение на уровне демона определять страну и отсылать уже в выше упомянутою страну ПОПЕНГАГЕН.

Первым делом, вооружившись гайдам, я скачать от сюда http://www.maxmind.com/app/geolitecountry latest GeoLite Country Binary Format (это бесплатный вариант базы стран и соответствующих им блоков IP адресов).
Распаковываем архив и кидаем файл GeIP.dat в папку
/usr/local/etc/nginx/conf/geo
если такой папки нет, создайте её или их.
Далее нужно отредактировать файл /etc/nginx/nginx.conf
секцию http в любом месте секции, вписываем
geoip_country /usr/local/etc/nginx/conf/geo/GeoIP.dat; # подключаем GeIP базу
    map $geoip_country_code $bad_country { # модуль map создает переменные, значения которых зависят от других переменных, очень полезная штука
    default 1; # значение по умолчанию
    include /usr/local/etc/nginx/conf/geo/good_countries; # инклудим файл, его нужно будет создать чуть позже
    }


Этот блок map, означает, что все страны находящиеся в базе данных, являются запрещенными по умолчанию, а в файле good_countries, будут перечислены разрешенные страны.

Теперь в файл настроек (мой это ) /etc/nginx/sites-avalible/default вписываем после
server {
listen       IP:80;
server_name  testhost.com;

вот этот код

if ($bad_country){ # если данная переменная установлена, то есть если страна не перечислена в файле good_countries
return 444; # выдаем клиенту пустой ответ ( незачем отдавать 403 ошибку или еще какую-либо )
}

Теперь создадим "тот файл", если хотяб краем глазом смотрели что вписываете, то увидели подключаемый файл
good_countries. Создаем его в директории /usr/local/etc/nginx/conf/geo/
И вписываем значения
UZ 0;
RU 0;

То есть тем самым разрешая вход на ваш сервер Узбекам и Русским. Ограничивать, точнее разрешать можно кому угодно, страны по двум буквам можно найти в гугле.
После того как все сделали, просто перезагружаем демон nginx.
Ну и собсно проверяем, зайдём через какой-нибудь веб прокси. И о чудо! действительно! Всё работает как надо.
Плюсом в корне сайта оставил php код который тоже смотрит по геопризнаку, и моментально отправляет на страницу с информацией и JS хитрой но не надёжной капчёй + предварительно буду записывать тех кто оказался в корне сайта.

Вот мой index.php

Код: (php) [Выделить]
<?php
 
include("country.php"); //этот файл уже расписан выше
 
$ip $_SERVER['REMOTE_ADDR'];
 
$geopoloj strana($ip);
 switch (
$geopoloj) {
  case 
"UA":
 
$goLoc "http://ТУТ_МОЙ_САЙТ_РЕДИРЕКТА/redirect/ua.html";
 break;
  case 
"EU":
 
$goLoc ="http://ТУТ_МОЙ_САЙТ_РЕДИРЕКТА/redirect/eu.html";
 break;
  case 
"FR":
 
$goLoc "http://ТУТ_МОЙ_САЙТ_РЕДИРЕКТА/redirect/fr.html";
 break;
 case 
"DE":
 
$goLoc "http://ТУТ_МОЙ_САЙТ_РЕДИРЕКТА/redirect/de.html";
 break;
 case 
"CN":
 
$goLoc "http://ТУТ_МОЙ_САЙТ_РЕДИРЕКТА/redirect/cn.html";
 break;
  case 
"RU":
 
$goLoc "index-verify.html"// тут логика, если страна разрешена, моментально переадресовывем на страницу
 
break;
   case 
"US":
 
$goLoc "http://ТУТ_МОЙ_САЙТ_РЕДИРЕКТА/redirect/eu.html";
 break;
  default:
 
$goLoc "index-verify.html"// тут логика, если страны нет в списке, значит она разрешена, моментально переадресовывем на страницу
 
}
 
header("location: $goLoc");
 
 
 
$user_agent $_SERVER['HTTP_USER_AGENT'];
 
function 
getOS() { 
 
    global 
$user_agent;
 
    
$os_platform  "Unknown OS Platform";
 
    
$os_array     = array(
                          
'/windows nt 10/i'      =>  'Windows 10',
                          
'/windows nt 6.3/i'     =>  'Windows 8.1',
                          
'/windows nt 6.2/i'     =>  'Windows 8',
                          
'/windows nt 6.1/i'     =>  'Windows 7',
                          
'/windows nt 6.0/i'     =>  'Windows Vista',
                          
'/windows nt 5.2/i'     =>  'Windows Server 2003/XP x64',
                          
'/windows nt 5.1/i'     =>  'Windows XP',
                          
'/windows xp/i'         =>  'Windows XP',
                          
'/windows nt 5.0/i'     =>  'Windows 2000',
                          
'/windows me/i'         =>  'Windows ME',
                          
'/win98/i'              =>  'Windows 98',
                          
'/win95/i'              =>  'Windows 95',
                          
'/win16/i'              =>  'Windows 3.11',
                          
'/macintosh|mac os x/i' =>  'Mac OS X',
                          
'/mac_powerpc/i'        =>  'Mac OS 9',
                          
'/linux/i'              =>  'Linux',
                          
'/ubuntu/i'             =>  'Ubuntu',
                          
'/iphone/i'             =>  'iPhone',
                          
'/ipod/i'               =>  'iPod',
                          
'/ipad/i'               =>  'iPad',
                          
'/android/i'            =>  'Android',
                          
'/blackberry/i'         =>  'BlackBerry',
                          
'/webos/i'              =>  'Mobile'
                    
);
 
    foreach (
$os_array as $regex => $value)
        if (
preg_match($regex$user_agent))
            
$os_platform $value;
 
    return 
$os_platform;
}
 
function 
getBrowser() {
 
    global 
$user_agent;
 
    
$browser        "Unknown Browser";
 
    
$browser_array = array(
                            
'/msie/i'      => 'Internet Explorer',
                            
'/firefox/i'   => 'Firefox',
                            
'/safari/i'    => 'Safari',
                            
'/chrome/i'    => 'Chrome',
                            
'/edge/i'      => 'Edge',
                            
'/opera/i'     => 'Opera',
                            
'/netscape/i'  => 'Netscape',
                            
'/maxthon/i'   => 'Maxthon',
                            
'/konqueror/i' => 'Konqueror',
                            
'/mobile/i'    => 'Handheld Browser'
                     
);
 
    foreach (
$browser_array as $regex => $value)
        if (
preg_match($regex$user_agent))
            
$browser $value;
 
    return 
$browser;
}
 
 
$user_os        getOS();
$user_browser   getBrowser();
 
 
 
print_r($device_details);
 
echo(
"<br /><br /><br />".$_SERVER['HTTP_USER_AGENT']."");
 
 
/*блок записи поситителей, с сохранением в *.html*/
$file fopen("base.html","a+");
$ip getenv(REMOTE_ADDR);
$details json_decode(file_get_contents("http://ipinfo.io/{$ip}/json"));
$time date("H:i:s  d M Y");
$url_o getenv(HTTP_REFERER);
$url_k getenv(REQUEST_URI);
$soft getenv(HTTP_USER_AGENT);
 
$all ="<=========><font color=green>############################################################</font><==========><br>IP: <font color=green><b>$ip</b></font><br>   Время и дата: <font color=blue><b>$time</b></font><br>  Перешёл с ссылки: <font color=Purple>$url_o</font> <br>Ядро браузера: <font color=red>$soft</font> <br>
Страна: <b>
$details->country</b><br>Регион: <b>$details->region </b><br>Город: <b>$details->city</b><br>Домен : <b>$details->hostname</b><br>$device_details Браузер: <b>$user_browser</b><br />Операциоинная система: <b>$user_os</b><br>На карте Google : <b><a href=https://www.google.com/search?q=$details->loc>посмотреть</a></b>;
<br><=========><font color=green>############################################################</font><==========><br><br>\r"
;
fwrite($file,$all );
fclose($file);
//$name=($_POST['namet']);
 
?>

Ну и собственно index-verify.html
(Нажмите, чтобы показать/скрыть)

И теперь спустя уже более 14 суток, тормозов замечено небыло. Всё работает как часы, тьфу тьфу тьфу.

Пример записи

Все css и js для страницы прикрепляю архивом css_js.zip https://yadi.sk/d/r5mKLAE83YzUxv
А так же выражаю огромную благодарность всем тем кто мне в тот момент помогал советом, так всем тем кто писал статьи, благодаря кому я смог собрать по крупицам и настроить себе сеть. Их много, а поэтому и прошу, если вы увидели что выноска или ваш конфиг написан тут, сообщите мне об этом, я обязательно укажу что права принадлежат Вам, возможно я это упустил, и поверьте статей было ооочень много перечитано.

Подводя итоги, скажу так. Если Вы сис админ, и Вас попросили создать нечто похожее, отнеситесь со всей серьёзностью к данному вопросу, так как потом, не дай бог конечно придётся побегать. Лучше 1 раз сначала настроить все по человечески, а уж потом курить бамбук.
Надеюсь данная статья поможет и Вам. Конечно это не супер защита от ддоса как у гугла, но как я смог это реализовать так и поделился с Вами. Статья так и называется Защита от DoS глазами новичка.

Если кому то понадобится помощь буду рад помочь, что в моих силах.
Так же принимаю аргументированную критику.
Спасибо за внимание!
Пример как он работает
https://www.youtube.com/watch?v=g_eG4oWVSWc
« Последнее редактирование: 11 Июля 2018, 10:38:30 от anomal3 »

 

Страница сгенерирована за 0.056 секунд. Запросов: 24.