Nginx защита от DDoS

Дата: 11.04.2019Метки:

В данной заметке речь пойдет о защите веб-сервера от DDoS. Наиболее часто для нарушения работы сайта злоумышленники используют HTTP-флуд. Для защиты от HTTP-флуда я буду использовать связку из Nginx и модуля nginx-module-testcookie. Все действия производились под CentOS 7, но данная заметка будет актуальна и для других систем за исключением этапа установки пакетов.

Для начала необходимо добавить репозиторий rpms.southbridge.ru в систему. Для этого выполните команду:

rpm -Uhv http://rpms.southbridge.ru/southbridge-rhel7-stable.rpm

Далее стандартной командой устанавливаем пакеты:

yum install nginx nginx-module-testcookie

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

wget http://rpms.southbridge.ru/rhel7/stable/x86_64/nginx-1.9.5-1.el7.centos.ngx.x86_64.rpm
wget http://rpms.southbridge.ru/rhel7/stable/x86_64/nginx-module-testcookie-1.15.6.1.24-1.el7.ngx.x86_64.rpm

Если в системе ранее уже был установлен Nginx, нужно его удалить. Устанавливаем Nginx и nginx-module-testcookie:

rpm -Uhv nginx-1.15.6-1.el7.ngx.x86_64.rpm
rpm -Uhv nginx-module-testcookie-1.15.6.1.24-1.el7.ngx.x86_64.rpm

Чтобы включить модуль добавьте строку ниже в файл /etc/nginx/nginx.conf:

Для включение и отключения testcookie нам необходимо периодически просматривать статистику подключений. Для этого добавьте в конфиг:

server {
    listen 80;
    server_name localhost;

    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

Применяем настройки, проверяем:

# service nginx restart
# curl http://localhost/nginx_status
Active connections: 4
server accepts handled requests
 137 137 190
Reading: 0 Writing: 1 Waiting: 3

Берем файл https://github.com/duy13/vDDoS-Protection/blob/master/aes.min.js.txt и копируем его в отдельный каталог на сервере /www/public_html/aes.min.js

Добавляем в конфиг вашего сайта следующие строки:

location = /aes.min.js {
    gzip on;
    gzip_min_length 1000;
    gzip_types text/plain;
    gzip_static on;
    root /www/public_html;
}

Сохраняем настройки:

nginx reload

Проверяем, что файл доступен по адресу http://site.ru/aes.min.js

Добавляем в конфиг вашего сайта параметры по примеру ниже:

http {
    testcookie off;
    testcookie_name RCPC;
    testcookie_secret nlos7m5hYc6gNmm7NvhCZJ8W7lJHuAaV2dp73px9diYMYzKmhvrpjZLNaoK989wW;
    testcookie_session $remote_addr;
    testcookie_arg attempt;
    testcookie_max_attempts 3;
    testcookie_get_only on;
    testcookie_redirect_via_refresh on;
    testcookie_refresh_encrypt_cookie on;
    testcookie_refresh_encrypt_cookie_key ea5891045bdfddd19682146f1e88e6e8;
    testcookie_refresh_encrypt_cookie_iv ea5891045bdfddd19682146f1e88e6e8;
    testcookie_refresh_template '<html><body>setting cookie...<script type=\"text/javascript\" src=\"/aes.min.js\" ></script><script>function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e="",f=0;f<d.length;f++)e+=(16>d[f]?"0":"")+d[f].toString(16);return e.toLowerCase()}var a=toNumbers("$testcookie_enc_key"),b=toNumbers("$testcookie_enc_iv"),c=toNumbers("$testcookie_enc_set");document.cookie="RCPC="+toHex(slowAES.decrypt(c,2,a,b))+"; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/";document.location.href="$testcookie_nexturl";</script></body></html>';



 server {
        listen 80;
        server_name test.com;

        location = /aes.min.js {
            gzip on;
            gzip_min_length 1000;
            gzip_types text/plain;
            root /var/www/public_html;
        }
        
        #Если используется проксирование, в противном случае не использовать
        location / {
            testcookie off;
            proxy_set_header   Host             $host;
            proxy_set_header   X-Real-IP        $remote_addr;
            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:80;
        }
    }

Параметр testcookie_secret заполняем случайным набором из 64 символов. Для testcookie_refresh_encrypt_cookie_key и testcookie_refresh_encrypt_cookie_iv генерируем hex число длиной 32 символа этим генератором.

Теперь осталось настроить скрипт, который будет автоматически проверять количество подключений к Nginx и в случае превышения лимита, автоматически включать testcookie и атпровлять уведомление администратору на почту.

#!/bin/sh

NGINX_CONF=/etc/nginx/conf.d/default.conf
MAIL="admin@site.ru"
MAILTO=root
LA_ACTIVATE=17
LA_DEACTIVATE=5
NGINX_CONNECT=1000

TMPLOG=/tmp/testcookie_module.tmp
NGINXCONN=`curl -s http://localhost/nginx-status | grep "Active" | awk '{print($3)}'`
LA=`cat /proc/loadavg | awk -F '.' '{print($1)}'`

function e {
    echo -en $(date "+%F %T"): "$1"
}

if [ ! -f $TMPLOG ];then echo 0 > $TMPLOG; fi
LASTRESULT=`cat $TMPLOG`

if [ -n "$NGINXCONN" ]; then
  if [ $NGINXCONN -gt $NGINX_CONNECT ]; then
    ALERT1="1"
  fi
fi

if [ -n "$LA" ]; then
  if [ $LA -gt $LA_ACTIVATE ]; then
    ALERT2="1"
  fi
fi

ALERT=$ALERT1$ALERT2

if [ -n "$ALERT" -a $LASTRESULT -eq 0 ]; then
    e; printf "Nginx connect: %-4s LA: %-3s | Activate testcookie\n" "$NGINXCONN" "$LA"
    sed -i 's/.*##-AUTO-DDOS-LABEL-##/\ttestcookie on; ##-AUTO-DDOS-LABEL-##/g' $NGINX_CONF
    /sbin/service nginx reload >/dev/null 2>&1
    echo 1 > $TMPLOG
    if [ "$MAIL" = "true" ];then
        echo "Nginx connect $NGINXCONN, LA $LA. Nginx test-cookie enable" | mail -s "`hostname` DDOS detected. Nginx test-cookie enable" $MAILTO
    fi
fi

if [ $LA -le $LA_DEACTIVATE -a $LASTRESULT -eq 1 ]; then
    e; printf "Nginx connect: %-4s LA: %-3s | Dectivate testcookie\n" "$NGINXCONN" "$LA"
    sed -i 's/.*##-AUTO-DDOS-LABEL-##/\ttestcookie off; ##-AUTO-DDOS-LABEL-##/g' $NGINX_CONF
    /sbin/service nginx reload >/dev/null 2>&1
    echo 0 > $TMPLOG
fi

Добавляем задание в cron:

* * * * *      /etc/nginx/check.sh >/dev/null 2>&1

Отключить обновления Windows 10

Дата: 11.04.2019Метки:

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

В данной заметке поделюсь проверенным на данный момент способом. Выполните в командной строке с правами администратора команду:

takeown /f c:\windows\system32\usoclient.exe /a

далее переходим в каталог C:\Windows\System32\, найдите usoclient.exe, нажмите по нему правой кнопкой мыши и выберите пункт Свойства. Поочередно выберите каждый пункт в списке Группы или пользователи и снимите для них все разрешения.

Warning: require(): open_basedir restriction in effect. File(x) is not within the allowed path(s)

Столкнулся с ошибкой во время переноса скрипта на другой сервер. Для управления сайтами используется панель Vesta CP. Проблема заключается в том, что на сервере не правильно прописана опция open_basedir. Для нормальной работы скрипта нам нужно обеспечить доступ к каталогу /home/system/web/system.ru/yii/.

Warning: require(): open_basedir restriction in effect. File(/home/system/web/system.ru/yii/vendor/autoload.php) is not within the allowed path(s): (/home/system/web/system.ru/public_html:/home/system/1) in /home/system/web/system.ru/public_html/admin/index.php on line 10

Warning: require(/home/system/web/system.ru/yii/vendor/autoload.php): failed to open stream: Operation not permitted in /home/system/web/system.ru/public_html/admin/index.php on line 10

Fatal error: require(): Failed opening required '/home/system/web/system.ru/public_html/admin/../../yii/vendor/autoload.php' (include_path='.:/usr/share/pear:/usr/share/php') in /home/system/web/system.ru/public_html/admin/index.php on line 10

Для решения проблемы Warning: require(): open_basedir restriction in effect. File(x) is not within the allowed path(s) переходим в каталог с конфигами Apache. У меня Vesta CP и они расположены по следующему пути:

cd /home/system/conf/web

Далее добавляем или правим настройки в конфигах:

system.ru.httpd.conf
system.ru.httpd.ssl.conf

Следующую опцию:

<Directory /home/system/web/system.ru/public_html>
        AllowOverride All
        SSLRequireSSL
        Options +Includes -Indexes +ExecCGI
        php_admin_value open_basedir   /home/system/web/system.ru/public_html:/home/system
        php_admin_value upload_tmp_dir /home/system/tmp
        php_admin_value session.save_path /home/system/tmp
    </Directory>

Поиск и замена в Linux

Дата: 03.04.2019

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

Для поиска и замены в Linux по указанному слову выполните команду:

grep -rli 'исходный текст' * | xargs -i@ sed -i 's/исходный текст/текст на который нужно заменить/g' @

Если нужно просто выполнить поиск по содержимому файлов без выполнения замены:

grep -rl 'исходный текст' /

Монтирование NTFS в Linux

Дата: 29.03.2019

Небольшая заметка на тему монтирования NTFS в Linux. Понадобилось мне скопировать файлы с диска, на котором была ранее установлена Windows. Монтирую как обычный раздел и получаю следующее сообщение:

# mount /dev/sda2 /1
The disk contains an unclean file system (0, 0).
The file system wasn't safely closed on Windows. Fixing.

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

Ошибка установки Windows 0х0000005

Дата: 26.03.2019

Во время установки Windows получил ошибку, содержимое окна указано ниже. Ошибку получал в самом конце конце копирования файлов. Ранее на этом железе уже была установлена система. Windows падала пару раз в день.

Непредвиденная ошибка установки Windows. Убедитесь в том, что источники установки доступны, и перезапустите установку. 
Код ошибки: 0xC0000005

Как оказалось проблема была связана с неисправным модулем оперативной памяти. Если столкнулись с подобной проблемой, просканируйте память. Либо попробуйте выполнить установку с одним проверенным модулем памяти.

Linux выполнять команду каждую секунду

Дата: 26.03.2019

Небольшая заметка на тему, как непрерывно выполнять одну и туже команду в Linux. Лично мне понадобилось при переносе файлов каждую секунду проверять размер каталога. В данном случае мне нужно было постоянно выполнять команду du -sh. Для выполнения любой команды через заданный промежуток времени в Linux есть утилита watch.

Параметры ее использования достаточно просты. Для примера мне нужно выполнить команду каждую 1-у секунду:

watch -n1 command

MySQL Server Has Gone Away

Дата: 15.02.2019Метки:

Во время загрузки дампа в phpMyAdmin столкнулся с ошибкой MySQL Server Has Gone Away. Дамп был размером на 10MB, а его экспорт требовал времени. В итоге срабатывал тайм-аут соединения, в результате чего сервер закрывал соединение. Для решения проблемы необходимо в файле my.cnf увеличить значение параметра wait_timeout.

vi /etc/mysql/my.cnf

Затем установить тайм-аут ожидания в секундах:

wait_timeout = 600

Настроить soft RAID0 в Linux

Дата: 11.02.2019Метки:

Для настройки soft RAID0 в Linux потребуется два раздела одинакового размера. В моем случае уже были подготовлены разделы, в случае их отсутствия вам создать дав одинаковых раздела на двух дисках. Весь процесс создания заключается всего в одной команде:

# mdadm -C /dev/md4 -l raid0 -n 2 /dev/nvme[0-1]n1p4
mdadm: /dev/nvme0n1p4 appears to contain an ext2fs file system
       size=376531904K  mtime=Sun Feb 10 21:31:56 2019
mdadm: /dev/nvme1n1p4 appears to contain an ext2fs file system
       size=376531904K  mtime=Sun Feb 10 21:31:56 2019
Continue creating array? y
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md4 started.

Просмотреть информацию о RAID массиве:

# mdadm -E /dev/nvme[0-1]n1p4
/dev/nvme0n1p4:
          Magic : a92b4efc
        Version : 1.2
    Feature Map : 0x0
     Array UUID : d798bc02:2e3b3241:ef4ac56e:f742e569
           Name : server:4  (local to host server)
  Creation Time : Mon Feb 11 05:08:40 2019
     Raid Level : raid0
   Raid Devices : 2

 Avail Dev Size : 752801792 (358.96 GiB 385.43 GB)
    Data Offset : 262144 sectors
   Super Offset : 8 sectors
   Unused Space : before=262056 sectors, after=0 sectors
          State : clean
    Device UUID : a0a31486:1d80a1ad:16728a55:5e91b47e

    Update Time : Mon Feb 11 05:08:40 2019
  Bad Block Log : 512 entries available at offset 72 sectors
       Checksum : 5e149378 - correct
         Events : 0

     Chunk Size : 512K

   Device Role : Active device 0
   Array State : AA ('A' == active, '.' == missing, 'R' == replacing)
/dev/nvme1n1p4:
          Magic : a92b4efc
        Version : 1.2
    Feature Map : 0x0
     Array UUID : d798bc02:2e3b3241:ef4ac56e:f742e569
           Name : server:4  (local to host server)
  Creation Time : Mon Feb 11 05:08:40 2019
     Raid Level : raid0
   Raid Devices : 2

 Avail Dev Size : 752801792 (358.96 GiB 385.43 GB)
    Data Offset : 262144 sectors
   Super Offset : 8 sectors
   Unused Space : before=262056 sectors, after=0 sectors
          State : clean
    Device UUID : ec2e8427:f2f506e8:c7895f2e:737b9873

    Update Time : Mon Feb 11 05:08:40 2019
  Bad Block Log : 512 entries available at offset 72 sectors
       Checksum : 7a29660 - correct
         Events : 0

     Chunk Size : 512K

   Device Role : Active device 1
   Array State : AA ('A' == active, '.' == missing, 'R' == replacing)
root@server:~# mdadm --detail /dev/nvme[0-1]n1p4
mdadm: /dev/nvme0n1p4 does not appear to be an md device
mdadm: /dev/nvme1n1p4 does not appear to be an md device
root@server:~# mdadm --detail /dev/md4
/dev/md4:
        Version : 1.2
  Creation Time : Mon Feb 11 05:08:40 2019
     Raid Level : raid0
     Array Size : 752801792 (717.93 GiB 770.87 GB)
   Raid Devices : 2
  Total Devices : 2
    Persistence : Superblock is persistent

    Update Time : Mon Feb 11 05:08:40 2019
          State : clean
 Active Devices : 2
Working Devices : 2
 Failed Devices : 0
  Spare Devices : 0

     Chunk Size : 512K

           Name : server:4  (local to host server)
           UUID : d798bc02:2e3b3241:ef4ac56e:f742e569
         Events : 0

    Number   Major   Minor   RaidDevice State
       0     259       10        0      active sync   /dev/nvme0n1p4
       1     259        4        1      active sync   /dev/nvme1n1p4

Создаем файловую систему:

# mkfs.ext4 /dev/md4
mke2fs 1.43.4 (31-Jan-2017)
Discarding device blocks: done
Creating filesystem with 188200448 4k blocks and 47054848 inodes
Filesystem UUID: 8d549021-4994-496d-90a0-ee53133036b1
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
        4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
        102400000

Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done

Далее монтируем командой:

mount /dev/md4 /home

Удалить soft RAID в Linux

Дата: 11.02.2019Метки:

После установки системы в soft RAID1 понадобилось мне изменить RAID для одного из разделов. Для удаления программного RAID первым делом нам нужно отмонтировать файловую систему, которая расположена на нем. В моем случае это был каталог /home.

umount /home

Останавливаем массив:

mdadm -S /dev/md4

В вашем случае md можем иметь другую нумерацию.
Смотрим информацию о разделах диска:

# fdisk -l
Disk /dev/nvme1n1: 419.2 GiB, 450098159616 bytes, 879097968 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3D66E75C-59E9-4551-A719-B417E617F076

Device             Start       End   Sectors   Size Type
/dev/nvme1n1p1      2048   1048575   1046528   511M EFI System
/dev/nvme1n1p2   1048576   2095103   1046528   511M Linux RAID
/dev/nvme1n1p3   2095104 124973055 122877952  58.6G Linux RAID
/dev/nvme1n1p4 124973056 878036991 753063936 359.1G Linux RAID
/dev/nvme1n1p5 878036992 879083519   1046528   511M Linux swap


Disk /dev/md3: 58.6 GiB, 62913445888 bytes, 122877824 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/md2: 511 MiB, 535756800 bytes, 1046400 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/nvme0n1: 419.2 GiB, 450098159616 bytes, 879097968 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: D921332C-5726-42B3-89E4-5771567C8A8A

Device             Start       End   Sectors   Size Type
/dev/nvme0n1p1      2048   1048575   1046528   511M EFI System
/dev/nvme0n1p2   1048576   2095103   1046528   511M Linux RAID
/dev/nvme0n1p3   2095104 124973055 122877952  58.6G Linux RAID
/dev/nvme0n1p4 124973056 878036991 753063936 359.1G Linux RAID
/dev/nvme0n1p5 878036992 879083519   1046528   511M Linux swap

В моем случае под программный RAID использовались разделы /dev/nvme1n1p4 и /dev/nvme0n1p4. Очищаем суперблоки RAID на разделах из которого собран массив:

mdadm --zero-superblock /dev/nvme1n1p4
mdadm --zero-superblock /dev/nvme0n1p4

Проверяем:

# mdadm --examine /dev/nvme1n1p4
mdadm: No md superblock detected on /dev/nvme1n1p4.
# mdadm --examine /dev/nvme0n1p4
mdadm: No md superblock detected on /dev/nvme0n1p4.

Удаление soft RAID в Linux выполнено успешно.