Выделенный Web-сервер на основе nginx – отличный способ повышения производительности Web-сайтов. В скорости обработки статического контента ему просто нет равных: он легко выдерживает несколько тысяч одновременных соединений и может быть легко оптимизирован и подогнан под любую конфигурацию. Однако? выступая в качестве фронт-энда для Apache, nginx оказывается наиболее уязвимым местом всей Web-инфраструктуры, поэтому безопасности nginx необходимо уделить особое внимание.

Эта статья – своего рода ликбез, или, если хочешь, резюме всех техник повышения безопасности nginx. В ней не будет теории, описания основ настройки Web-сервера и прочей воды. Вместо этого ты получишь исчерпывающий практический материал, описывающий все основные шаги, которые необходимо проделать для того, чтобы получить по-настоящему защищенный Web-сервер.

Установка

Пакет nginx доступен в прекомпилированном виде для любого дистрибутива. Однако собрав сервер самостоятельно, ты сможешь сделать его более компактным и надежным, а также получишь возможность изменить строку приветствия Web-сервера, чтобы отбить несмышленых скрипт-кидди.

Измени строку приветствия Web-сервера

Скачай исходники nginx, открой файл src/http/ngx_http_header_filter_module.c и найди следующие две строки:

static char ngx_http_server_string[] = "Server: nginx" CRLF;
static char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF;

Замени их на что-то вроде этого:

static char ngx_http_server_string[] = "Server: ][ Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: ][ Web Server" CRLF;

Удали все неиспользуемые тобой nginx-модули

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

Выполни сборку с помощью следующих команд:

# ./configure --without-http_autoindex_module --without-http_ssi_module
# make

# make install

Так ты получишь nginx с заранее отключенными (и в большинстве случаев бесполезными) модулями SSI (Server Side Includes) и Autoindex. Чтобы узнать, какие модули можно безболезненно выбросить из Web-сервера, запусти скрипт configure с флагом ‘–help’.

Препарируем nginx.conf

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

Отключи показ версии сервера на всех ошибочных страницах

Добавь в файл nginx.conf строку «server_tokens off». Это заставит nginx скрывать информацию о типе и версии Web-сервера на страницах, генерируемых в ответ на ошибочный запрос клиента.

Настрой защиту от срыва стека

Добавь в секцию server следующие строки:

# vi /etc/nginx/nginx.conf

# Максимальный размер буфера для хранения тела запроса клиента
client_body_buffer_size 1K;
# Максимальный размер буфера для хранения заголовков запроса клиента
client_header_buffer_size 1k;
# Максимальный размер тела запроса клиента, прописанный в поле Content-Length заголовка. Если сервер должен поддерживать загрузку файлов, это значение необходимо увеличить
client_max_body_size 1k;
# Количество и размер буферов для чтения большого заголовка запроса клиента
large_client_header_buffers 2 1k;

Обрати внимание на директиву large_client_header_buffers. По умолчанию, для хранения строки URI nginx выделяет четыре буфера, размер каждого из которых равен размеру страницы памяти (для x86 это 4 Кб). Буферы освобождаются каждый раз, когда по окончанию обработки запроса соединение переходит в состояние keep-alive. Два буфера по 1 Кб могут хранить URI длиной только 2 Кб, что позволяет бороться с ботами и DoS-атаками.

Для повышения производительности добавь следующие строки:

# vi /etc/nginx/nginx.conf

# Таймаут при чтении тела запроса клиента
client_body_timeout 10;
# Таймаут при чтении заголовка запроса клиента
client_header_timeout 10;
# Таймаут, по истечению которого keep-alive соединение с клиентом не будет закрыто со стороны сервера
keepalive_timeout 5 5;
# Таймаут при передаче ответа клиенту
send_timeout 10;

Контролируй количество одновременных соединений

Для защиты Web-сервера от перегрузки и попыток осуществить DoS-атаку добавь в конфиг следующие строки:

# vi /etc/nginx/nginx.conf

# Описываем зону (slimits), в которой будут храниться состояния сессий. Зона размером 1 Мб может хранить около 32000 состояний, мы устанавливаем ее размер равным 5 Мб
limit_zone slimits $binary_remote_addr 5m;
# Задаем максимальное количество одновременных соединений для одной сессии. По сути, это число задает максимальное количество соединений с одного IP
limit_conn slimits 5;

Первая директива должна находиться в секции HTTP, вторая – в секции location. Когда количество соединений выйдет за пределы лимитов, клиент получит сообщение «Service unavailable» с кодом 503.

Разреши коннекты только к своему домену

Взломщики могут использовать ботов для сканирования подсетей и поиска уязвимых Web-серверов. Обычно боты просто перебирают диапазоны IP-адресов в поисках открытых 80 портов и посылают запрос HEAD для получения информации о веб-сервере (или главной странице). Ты можешь легко предотвратить такой скан, запретив обращение к серверу по IP-адресу (добавить в подсекцию location):

# vi /etc/nginx/nginx.conf

if ($host !~ ^(host.com|www.host.com)$ ) {
return 444;
}

Ограничь количество доступных методов обращения к Web-серверу

Некоторые боты используют различные методы обращения к серверу для попытки определения его типа и/или проникновения, однако в документе RFC 2616 четко сказано, что Web-сервер не обязан реализовывать их все, и неподдерживаемые методы могут просто не обрабатываться. Сегодня используемыми остаются только методы GET (запрос документа), HEAD (запрос заголовков сервера) и POST (запрос на публикацию документа), поэтому все остальные можно безболезненно отключить с помощью помещения следующих строк в секцию server конфигурационного файла:

# vi /etc/nginx/nginx.conf

if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444;
}

Отшивай ботов

Другой способ блокирования ботов, сканеров и прочей нечисти основан на определении типа клиента (user-agent). Он не слишком эффективен, потому как большинство ботов косят под вполне легитимные браузеры, но в ряде случаев остается полезным:

# vi /etc/nginx/nginx.conf

# Блокируем менеджеры загрузки
if ($http_user_agent ~* LWP::Simple|BBBike|wget) {
return 403;
}
# Блокируем некоторые типы ботов
if ($http_user_agent ~* msnbot|scrapbot) {
return 403;
}

Блокируй Referrer-спам

Если твой сайт публикует Web-логи в общедоступном виде, ты легко можешь стать жертвой Referrer-спама (когда спам-боты обращаются к твоему серверу, указывая в заголовке referrer – адрес рекламируемого сайта). Такой вид спама может легко испортить SEO-рейтинги интернет-страницы, поэтому его необходимо блокировать в обязательном порядке. Один из способов сделать это – занести наиболее частые слова, встречающиеся в адресах рекламируемых сайтов, в черный список.

# vi /etc/nginx/nginx.conf

# Секция server
if ( $http_referer ~* (babes|forsale|girl|jewelry|love|nudit|organic|poker|porn|sex|teen) )
{
return 403;
}

Блокируй хотлинк

Хотлинк – это включение в страницу изображения (или иного контента) с другого сайта. По сути, это воровство, потому как изображение, на которое ты потратил не один час своего свободного времени, не только свободно используется другими, но и создает нагрузку на твой Web-сервер, не приводя на него посетителей. Для борьбы с хотлинками достаточно сделать так, чтобы изображения отдавались клиенту только в том случае, если он запросил их, уже находясь на сайте (другими словами, заголовок referrer-запроса должен содержать имя твоего сайта). Добавь в секцию server конфигурационного файла nginx.conf следующие строки (host.com – это адрес твоего сайта):

# vi /etc/nginx/nginx.conf

location /images/ {
valid_referers none blocked www.host.com host.com;
if ($invalid_referer) {
return 403;
}
}

В качестве альтернативы ты можешь настроить сервер на отдачу специального баннера с сообщением о воровстве вместо запрашиваемого изображения. Для этого замени строку «return 403» на строку:

rewrite ^/images/uploads.*.(gif|jpg|jpeg|png)$ http://www.host.com/banned.jpg last

Защищай важные каталоги от посторонних

Как и любой другой Web-сервер, nginx позволяет регулировать доступ к каталогам на основе IP-адресов и паролей. Эту возможность можно использовать для закрытия некоторых частей сайта от посторонних глаз. Например, для отрезания URI от внешнего мира:

# vi /etc/nginx/nginx.conf

location /uploads/ {
# Разрешаем доступ только машинам локальной сети
allow 192.168.1.0/24;
# Отшиваем всех остальных
deny all;
}

Теперь к документам каталога uploads будут иметь доступ только пользователи локальной сети. Для установки пароля придется проделать более сложные действия. Сначала необходимо создать приватный для nginx-файл паролей и добавить в него необходимых пользователей (в качестве примера добавим пользователя admin):

# mkdir /etc/nginx/.htpasswd
 # htpasswd -c /etc/nginx/.htpasswd/passwd admin

Далее открой файл nginx.conf и впиши в него следующие строки:

# vi /etc/nginx/nginx.conf
location /admin/ {
 auth_basic "Restricted";
 auth_basic_user_file /etc/nginx/.htpasswd/passwd;
 }

Новых пользователей можно добавить с помощью следующей команды:

# htpasswd -s /etc/nginx/.htpasswd/passwd пользователь

Используй SSL

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

Для настройки SSL-шифрования средствами nginx достаточно выполнить несколько простых шагов. Сначала ты должен создать сертификат с помощью следующей последовательности команд:

# cd /etc/nginx
 # openssl genrsa -des3 -out server.key 1024
 # openssl req -new -key server.key -out server.csr
 # cp server.key server.key.org
 # openssl rsa -in server.key.org -out server.key
 # openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Затем описать сертификат в конфигурационном файле nginx:

# vi /etc/nginx/nginx.conf
server {
 server_name host.com;
 listen 443;
 ssl on;
 ssl_certificate /etc/nginx/server.crt;
 ssl_certificate_key /etc/nginx/server.key;
 access_log /etc/nginx/logs/ssl.access.log;
 error_log /etc/nginx/logs/ssl.error.log;
 }

После этого можно перезагрузить Web-сервер:

# /etc/init.d/nginx reload

Естественно, без поддержки со стороны самого Web-сайта это делать бессмысленно.

Другие способы

Установи правильные значения системных переменных

Открой файл /etc/sysctl.conf и помести в него следующие строки:

# vi /etc/sysctl.conf
# Защита от smurf-атак
 net.ipv4.icmp_echo_ignore_broadcasts = 1
 # Защита от неправильных ICMP-сообщений
 net.ipv4.icmp_ignore_bogus_error_responses = 1
 # Защита от SYN-флуда
 net.ipv4.tcp_syncookies = 1
 # Запрещаем маршрутизацию от источника
 net.ipv4.conf.all.accept_source_route = 0
 net.ipv4.conf.default.accept_source_route = 0
 # Защита от спуфинга
 net.ipv4.conf.all.rp_filter = 1
 net.ipv4.conf.default.rp_filter = 1
 # Мы не маршрутизатор
 net.ipv4.ip_forward = 0
 net.ipv4.conf.all.send_redirects = 0
 net.ipv4.conf.default.send_redirects = 0
 # Включаем ExecShield
 kernel.exec-shield = 1
 kernel.randomize_va_space = 1
 # Расширяем диапазон доступных портов
 net.ipv4.ip_local_port_range = 2000 65000
 # Увеличиваем максимальный размер TCP-буферов
 net.ipv4.tcp_rmem = 4096 87380 8388608
 net.ipv4.tcp_wmem = 4096 87380 8388608
 net.core.rmem_max = 8388608
 net.core.wmem_max = 8388608
 net.core.netdev_max_backlog = 5000
 net.ipv4.tcp_window_scaling = 1

Размести корневой каталог Web-сервера на выделенном разделе

Поместив корневой каталог Web-сервера в выделенный раздел и запретив на нем размещение любых исполняемых файлов и файлов-устройств, ты обезопасишь остальную часть системы от тех, кто сможет получить доступ к корню Web-сервера. При этом запись в файле /etc/fstab должна иметь примерно такой вид:

/dev/sda5 /nginx ext4 defaults,nosuid,noexec,nodev 1 2

Помести nginx в chroot/jail-окружение

Любая современная *nix-система позволяет запереть приложение в изолированной среде исполнения. В Linux для этого можно использовать технологии KVM, Xen, OpenVZ и VServer, во FreeBSD – Jail, в Solaris – Zones. Если ни одна из этих технологий не доступна, ты можешь поместить nginx в классический chroot, который хоть и намного более хрупок, но большинство взломщиков остановить сможет.

Установи правила SELinux для защиты nginx

Хорошей альтернативой изолированным средам исполнения являются локальные системы обнаружения и предотвращения вторжений, такие как SELinux или AppArmor. Будучи правильно настроенными, они смогут предотвратить попытки взлома Web-сервера. По дефолту ни одна из них не настроена для работы в связке с nginx, однако в рамках проекта SELinuxNginx(http://sf.net/projects/selinuxnginx/) были созданы правила для SELinux, которые может использовать любой желающий. Остается только скачать и установить:

# tar -zxvf se-ngix_1_0_10.tar.gz
# cd se-ngix_1_0_10/nginx
# make
# /usr/sbin/semodule -i nginx.pp

Настрой брандмауэр

Обычно nginx устанавливают на выделенных машинах, готовых к высокой нагрузке, поэтому зачастую он остается единственным сетевым сервисом, работающим на сервере. Чтобы обезопасить сервер, достаточно создать совсем небольшой набор правил, которые будут открывать 80, 110 и 143-й порты (если, конечно, nginx должен работать еще и как IMAP/POP3-прокси) и закрывать от внешнего мира все остальное.

Ограничь количество соединений с помощью брандмауэра

Для не слишком нагруженного Web-сайта хорошей идеей будет ограничить количество попыток соединений с одного IP-адреса в минуту. Это сможет уберечь тебя от некоторых типов DoS-атак и брутфорса. В Linux это можно сделать с помощью стандартного iptables/netfilter-модуля state:

# iptables -A INPUT -p tcp --dport 80 -i eth0
 -m state --state NEW -m recent --set
 # iptables -A INPUT -p tcp --dport 80 -i eth0
 -m state --state NEW -m recent --update
 --seconds 60 --hitcount 15 -j DROP

Правила урезают лимит на количество подключений с одного IP в минуту до 15. То же можно сделать и с помощью pf:

# vi /etc/pf.conf
webserver_ip="1.1.1.1"
 table <abuse> persist
 block in quick from <abuse>
 pass in on $ext_if proto tcp to $webserver_ip
 port www flags S/SA keep state
 (max-src-conn 100, max-src-conn-rate 15/60,
 overload <abusive_ips> flush)

Кроме лимита на количество последовательных подключений (15 в минуту), данное правило устанавливает дополнительный лимит на количество одновременных подключений равный 100.

Настрой PHP

Если ты используешь nginx в связке с PHP, не забудь настроить и его. Вот как должен выглядеть конфигурационный файл /etc/php/php.ini защищенного сервера:

# vi /etc/php/php.ini

# Отключаем опасные функции
disable_functions = phpinfo, system, mail, exec
# Максимальное время исполнения скрипта
max_execution_time = 30
# Максимальное время, которое может потратить скрипт на обработку данных запроса
max_input_time = 60
# Максимальное количество памяти, выделяемое каждому скрипту
memory_limit = 8M
# Максимальный размер данных, отсылаемых скрипту с помощью метода POST
post_max_size = 8M
# Максимальный размер загружаемых файлов
upload_max_filesize = 2M
# Не показывать ошибки PHP-скриптов пользователям
display_errors = Off
# Включаем Safe Mode
safe_mode = On
# Включаем SQL Safe Mode
sql.safe_mode = On
# Позволяем выполнять внешние команды только в этом каталоге
safe_mode_exec_dir = /путь/к/защищенному/каталогу
# Защищаемся от утечки информации о PHP
expose_php = Off
# Ведем логи
log_errors = On
# Запрещаем открытие удаленных файлов
allow_url_fopen = Off

Выводы

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

https://xakep.ru/2010/12/15/54168/

приступаем к настройке.

# обновляем список пакетов и установим mc (дело вкуса, но я его ставлю)

apt-get update
apt-get install mc

# установим openvpn и приступим к настройке

apt-get install openvpn
cd /usr/share/doc/openvpn/examples/easy-rsa/2.0/

# редактируем переменные

nano ./vars

# меняем строки

export KEY_SIZE=1024  # Длинна ключа
export KEY_EXPIRE=3650 # Срок действия ключа в днях

# описание сертификатов по-умолчанию

export KEY_COUNTRY="RU"
export KEY_PROVINCE="RU"
export KEY_CITY="Moscow"
export KEY_ORG="http://habrahabr.ru"
export KEY_EMAIL="org@example.com"

# сохраняем файл

# инициализируем переменные и чистим папку keys и создаем сертификаты

. ./vars
. ./clean-all
./build-ca			# корневой сертификат
./build-key-server server	# сертификат сервера
./build-dh			# ключ Диффи Хельман

# если вы планируете использовать tls-auth, который позволит скрыть порт на котором сервер слушает vpn подключения, защитить от DoS атак и кое чего еще, то выполните еще и эту строку:

openvpn --genkey --secret ./keys/ta.key

# Включили tls-auth? Тогда не забудьте передать ta.key клиентам, его надо будет положить рядом с сертификатом пользователя. # перенесем полученные сертификаты в рабочую папку

cp ./keys/ca.crt /etc/openvpn
cp ./keys/server.crt /etc/openvpn
cp ./keys/server.key /etc/openvpn
cp ./keys/dh1024.pem /etc/openvpn

# Для tls-auth, выполните и эту строку:

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

./build-key-pkcs12 vpn.android
./build-key-pkcs12 vpn.windows
./build-key-pkcs12 vpn.debian
./build-key-pkcs12 vpn.ddwrt
./build-key-pkcs12 vpn.home

# после этого в папке /usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/ появятся ваши сертификаты vpn.android.*, vpn.windows.* и другие.

# Если захотите создать сертификаты поздней, подключаетесь по SSH, и:

#	cd /usr/share/doc/openvpn/examples/easy-rsa/2.0/
#	. ./vars
#	./build-key-pkcs12 vpn.newuser1
#	./build-key-pkcs12 vpn.newuser2

# настроим сервер

zcat /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz > /etc/openvpn/server.conf
nano /etc/openvpn/server.conf

# все настройки по-умолчанию нас устроят, меняем, раскомментируем:

    local IP_АДРЕС_ВАШЕГО_СЕРВЕРА
    push "redirect-gateway def1 bypass-dhcp"
    push "dhcp-option DNS 8.8.8.8"
    push "dhcp-option DNS 8.8.4.4"
    client-to-client # раскомментируйте, если хотите иметь доступ между клиентами внутри вашего VPN

# Для включения tls-auth, необходимо добавить (без #)

    # tls-auth ta.key 0

# Если хотите спрятать сервер от китайских ботов и ФСБ, поменяйте стандартный порт, на любой другой. Только не забудьте прописать этот же порт в настройках клиента.

    port 1194

# сохраняем

# применим настройки файрвола через rc.local, можно сделать иначе, но я остановился на этом варианте.

nano /etc/rc.local

# добавляем строки до exit 0

    iptables -A FORWARD -s 10.8.0.0/24 -j ACCEPT
    iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
    iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

# сохраняем

nano /etc/sysctl.conf

# раскомментируем строчку

    net.ipv4.ip_forward=1

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

reboot

Всё, серверная часть готова. Можно подключаться. Для перехода к следующим этапам, надо выгрузить с нашего сервера сертификаты из папки:

/usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/

Это можно сделать при помощи SSH, либо mc если у вас есть ftp сервер. Нам нужны только некоторые файлы, какие именно читаем ниже.

Настройка android клиента (root не требуется)

1. Устанавливаем на телефон OpenVPN for Android
2. Загружаем на карту памяти сертификат p12, брать тут

/usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/vpn.android.p12

3. Запускаем OpenVPN for Android
4. VPN Profiles > Add, вводим любое имя. Приступаем к настройке профиля:

  • Basic > Server Address: IP адрес вашего VPN сервера, либо имя домена если вы его привязали
  • Type: PKCS12 File
  • Select: Выбираем наш файл *.p12
  • PKCS12 Password: вводим пароль импорта сертификата, заданный при его генерации.
  • upd: используйте последнюю версию приложения, в ней проверка remote-cert-tls server включена по-умолчанию. либо включите вручную в настройках авторизации, проверку сертификата сервера
  • Если вы включили tls-auth на сервере, включите в настройках профиля tls-auth и выберите ta.key

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

Настройка Windows клиента

1. Скачиваем и устанавливаем клиент: 32bit | 64bit
2. Создаем файл конфигурации myvpnconfig.ovpn (обычный текстовый файл):

remote IP_вашего_сервера 1194
client
dev tun
ping 10
comp-lzo
proto udp
tls-client
remote-cert-tls server
pkcs12 vpn.windows.p12
verb 3
pull

 

# Если вы включили tls-auth на сервере, добавьте в конфиг эту строку:
tls-auth ta.key 1

3. Создаем batch скрипт (start_my_vpn.cmd) для запуска VPN сессии:

cd C:somepathopenvpn
"C:Program FilesOpenVPNbinopenvpn.exe" --config C:somepathopenvpnmyvpnconfig.ovpn

4. Скрипт и конфиг ложим в одну папку, в эту же папку кидаем vpn.windows.p12 сертификат, брать его тут

/usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/vpn.windows.p12

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

Если пароль верный, то несколько секунд и мы подключились:

Для не параноиков или автостарта туннеля без ввода пароля, можно вместо p12 использовать связку сертификатов ca.crt, vpn.windows.key и vpn.windows.crt, выглядит это так,
вместо

pkcs12 vpn.windows.p12

пишем:

ca ca.crt
cert vpn.windows.crt
key vpn.windows.key

Файлы брать все там же

/usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/

и положить в папку с myvpnconfig.ovpn и start_my_vpn.cmd.

Настройка Linux клиента

Настройка на примере debian 6.0

# ставим пакет openvpn
apt-get install openvpn

# создаем папку, в любом удобном месте для хранения сертификатов и скрипта подключения к VPN
mkdir /opt/openvpn

# создаем скрипт подключения
echo 'cd /opt/openvpn
/usr/sbin/openvpn --config /opt/openvpn/myvpnconfig.ovpn
' > /opt/openvpn/start_vpn.run

# создаем файл конфигурации
echo 'remote IP_ВАШЕГО_СЕРВЕРА 1194
client
dev tun
ping 10
comp-lzo
proto udp
tls-client
remote-cert-tls server
pkcs12 vpn.debian.p12
verb 3
pull' > /opt/openvpn/myvpnconfig.ovpn

# Если вы включили tls-auth на сервере, добавьте в конфиг эту строку:
# tls-auth ta.key 1

# vpn.debian.p12 берем как обычно на сервере /usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/
# опять же, можно вместо p12 использовать ca.crt, vpn.debian.key и vpn.debian.crt, как в примере с windows, для того чтобы не вводить пароль для подключения к VPN, это пригодиться например для автозапуска VPN.
chmod +x /opt/openvpn/start_vpn.run

Готово. Не забудьте положить vpn.debian.p12 или ca.crt, vpn.debian.key и vpn.debian.crt в папку со скриптом и файлом конфигурации.
Для подключения к VPN, просто выполните с повышенными привилегиями:

/opt/openvpn/start_vpn.run

 

Настройка роутера на dd-wrt (Big или Mega)

В данном случае будет проведена настройка роутера, как клиента сети VPN, для возможности удаленного подключения к роутеру, если подключение по внешнему адресу недоступно, например провайдер внезапно выдал вам NAT'ированный IP. Подключаться можно будет с любого устройства, внутри вашего VPN.

1. Перейдите на страницу router_ip/Diagnostics.asp (тех.обслуживание->команды)
2. Если у вас уже есть «Параметры запуска», то нажмите Редактировать и добавьте ниже приведенный код, после, либо до вашего. Если нет то просто вставьте его в «Командный процессор» и нажмите «Сохранить параметры запуска»
3. Собственно сам код запуска:

#### CERT ####
CA_CRT='-----BEGIN CERTIFICATE-----
C4dczC6ZeWIgri7krQzPIrX5hNYAc676PNv6iomNWVJNkugr
-----END CERTIFICATE-----'

CLIENT_CRT='-----BEGIN CERTIFICATE-----
C4dczC6ZeWIgri7krQzPIrX5hNYAc676PNv6iomNWVJNkugr
-----END CERTIFICATE-----'

CLIENT_KEY='-----BEGIN RSA PRIVATE KEY-----
C4dczC6ZeWIgri7krQzPIrX5hNYAc676PNv6iomNWVJNkugr
-----END RSA PRIVATE KEY-----'
#### CERT ####

#### OPEN VPN ####
OPVPNENABLE=`nvram get openvpncl_enable | awk '$1 == "0" {print $1}'`

if [ "$OPVPNENABLE" != 0 ]
then
   nvram set openvpncl_enable=0
   nvram commit
fi

sleep 30
mkdir /tmp/openvpn; cd /tmp/openvpn

echo "$CA_CRT" > ca.crt
echo "$CLIENT_CRT" > client.crt
echo "$CLIENT_KEY" > client.key

chmod 644 ca.crt client.crt
chmod 600 client.key

sleep 30

echo 'remote IP_ВАШЕГО_СЕРВЕРА 1194
client
dev tun
ping 10
comp-lzo
proto udp
tls-client
remote-cert-tls server
ca ca.crt
cert client.crt
key client.key
verb 3
pull' > openvpn.conf

# Если вы включили tls-auth на сервере, добавьте в конфиг эту строку:
# tls-auth ta.key 1

killall openvpn
openvpn --config /tmp/openvpn/openvpn.conf&
### MASQUERADE
iptables -I FORWARD -i br0 -o tun0 -j ACCEPT
iptables -I FORWARD -i tun0 -o br0 -j ACCEPT
iptables -I INPUT -i tun0 -j ACCEPT
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
###

4. Переменные CA_CRT, CLIENT_CRT и CLIENT_KEY, это содержимое файлов ca.crt, vpn.ddwrt.crt и vpn.ddwrt.key соответственно, просто открывайте их текстовым редактором и копируйте содержимое, в vpn.ddwrt.crt блок будет в самом конце, в двух других копируем содержимое полностью. Брать файлы известно где

/usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/

5. Не забудьте заменить IP_ВАШЕГО_СЕРВЕРА и нажать «Сохранить параметры запуска».
6. Перезагружаем роутер, пробуем подключиться к нему с другого устройства в вашем VPN. Посмотреть VPN IP адрес роутера можно например через ifconfig.

Помимо прочего, вы получаете возможность подключаться между устройствами, даже если они находятся за NAT провайдера, это очень удобно. Если конечно вы раскомментировали строку client-to-client в конфиге сервера.

Ограничение количества подключений

Для защиты от brute force (перебора паролей), можно ограничить количество подключений на 22 порт с одного ip адреса до нескольких раз в минуту, после чего блокировать попытки подключения для данного ip.

## Создание цепочки правил sshguard
# Максимум 2 новых запроса в минуту для одного ip
/sbin/iptables -N sshguard
# Вкл. лог по желанию
#/sbin/iptables -A sshguard -m state --state NEW -m recent --name SSH --rcheck --seconds 60 --hitcount 2 -j LOG --log-prefix "SSH-shield: "
/sbin/iptables -A sshguard -m state --state NEW -m recent --name SSH --update --seconds 60 --hitcount 2 -j DROP
/sbin/iptables -A sshguard -m state --state NEW -m recent --name SSH --set -j ACCEPT
/sbin/iptables -A sshguard -j ACCEPT
 
## Применение для трафика ssh цепочку sshguard
/sbin/iptables -A INPUT -p tcp --dport 22 -j sshguard

recent — это модуль ядра (Core Netfilter Configuration), позволяет создавать динамические списки адресов IP. Модуль поддерживает ряд опций

  • --name name : имя списка, с которым работает команда. По умолчанию для списка используется имя DEFAULT
  • --rcheck : опция будет проверять наличие адреса отправителя пакета в списке При отсутствии адреса в списке возвращается значение false.
  • --update : опция будет проверять наличие адреса отправителя пакета в списке. Если адрес присутствует, соответствующая запись обновляется. При отсутствии адреса в списке возвращается значение false.
  • --hitcount hits : счетчик, возвращает true при наличии адреса в списке, когда число принятых пакетов с адреса больше или равно заданного значения. Используется совместно с rcheck или update
  • --seconds seconds : определяет период (от момента занесения адреса в список), в течение которого адрес может находиться в списке
  • --set : служит для добавления адреса отправителя пакета в список. Если такой адрес уже есть в списке, запись будет обновлена
  • --remove : удалить адрес из списка. Если адрес не обнаружен вернет false.

Опции могут использоваться с инверсией (!)

Использование update, а не rcheck, заставляет выдержать интервал перед следующий попыткой подключения. Если не выдержав интервал сделать попытки подключения, то это приведет к тому, что придется выдержать снова 60 секунд с момента последний попытки подключения.

Динамическое открытие/закрытие ssh порта

Небольшое правило для iptables помогающее лишний раз не держать порты открытыми.

Пример для доступа к SSH, хотя как сами понимаете можно использовать как угодно.

Суть правила проста — для того чтобы открыть доступ к шеллу нужно сначала стукнуться на 1500 порт:
telnet'ом например:

telnet myserver 1500

или через браузер:

http://192.168.0.100:1500

соответственно если стукнуть на 1499 — то порт закроется

iptables -N sshguard
# Если адрес в списке, то подключение разрешено
iptables -A sshguard -m state --state NEW -m recent --rcheck --name SSH -j ACCEPT
# Разрешить пакеты для уже установленных соединений
iptables -A sshguard -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A sshguard -j DROP
 
# Заносит адрес в список
#iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 1500 -j LOG --log-prefix "SSH-open: "
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 1500 -m recent --name SSH --set -j DROP
# Удаляет адрес из списка
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 1499 -m recent --name SSH --remove -j DROP
 
# Применение для трафика ssh цепочку sshguard
iptables -A INPUT -p tcp --dport 22 -j sshguard
Порт открывается только для ip с которого был открыт

Открытие порта ssh на заданное время

Еще один пример демонстрирует способ открытия порта ssh для определенного ip на заданное время.

## определяем цепочку для SSH трафика
iptables -N sshguard
iptables -F sshguard
# Разрешить подключение если ip есть в списке и последнее подключение осуществлялось не позднее 108000 секунд (30 часов) 
iptables -A sshguard -m state --state NEW -m recent --update --seconds 108000 --name SSH -j ACCEPT
# Разрешить пакеты для уже установленных соединений
iptables -A sshguard -m state --state ESTABLISHED,RELATED -j ACCEPT
# Заблокировать если нет в списке
iptables -A sshguard -j DROP
 
## Открытие SSH
iptables -A INPUT -m state --state NEW -p tcp --dport 222 -m recent --name SSH --set
## Фильтрация ssh трафика через цепочку sshguard
iptables -A INPUT -p tcp --dport 22 -j sshguard

Теперь, чтобы получить ssh доступ нужно сперва постучаться на порт 222, например так:

ssh user@server.name -p 222

после этого доступ для вашего ip на 22 порт будет разрешен на указанное время, при этом каждый новый коннект на ssh будет продлевать это время. Если вы не хотите продления времени то замените --update --seconds 108000 на --rcheck.

Порт открывается только для ip с которого был открыт

Также можно узнать каким ip адресам разрешен доступ к ssh:
cat /proc/net/ipt_recent/SSH

UPDATE [LOW_PRIORITY] [IGNORE] tbl_name
    SET col_name1=expr1 [, col_name2=expr2, ...]
    [WHERE where_definition]
    [LIMIT #]
tbl_name
— Задает имя таблицы, в которой будут обновляться записи. На момент запуска команды UPDATE таблица с таким именем должна существовать в базе данных.
LOW_PRIORITY
— Если указан этот параметр, то обновление записи будет отложена до тех пор, пока другие сценарии не закончат чтение из этой таблицы.
IGNORE
— Если некоторые поля таблицы имеют ключи PRIMARY или UNIQUE, и производится обновление строки, в которой эти поля имеют дублирующее значение, то действие команды аварийно завершается и выдается ошибка №1062 («Duplicate entry 'val' for key N»). Если в команде INSERT указано ключевое слово IGNORE, то обновление записей не прерывается, а строки с дублирующими значениями просто не изменяются.
SET
— После этого ключевого слова должен идти список полей таблицы, которые будут обновлены и непосредственно сами новые значения полей в виде:
имя поля='значение'
Следующий пример производит обновление поля country у ВСЕХ записей в таблице users:
1UPDATE
2    `users`
3SET
4    `country`='Russia'
А здесь обновление полей country и city у ВСЕХ записей таблицы users:
1UPDATE
2    `users`
3SET
4    `country`='Russia',
5    `city`='Ryazan'
Если новое значение, присваиваемое командой UPDATE соответствует старому, то обновление этого поля не происходит.
Для задания нового значения можно использовать выражения.
Следующий пример увеличит возраст всех пользователей, записанных в таблице users на один год:
1UPDATE
2    `users`
3SET
4    `age`=`age`+1
WHERE
— Задает условие отбора записей, подлежащих изменению.
Следующий пример изменит название города в записях пользователей с «Ryazan» на «Рязань»:
1UPDATE
2    `users`
3SET
4    `city`='Рязань'
5WHERE
6    `city`='Ryazan'
LIMIT
— Задает максимальное количество строк, которые могут быть изменены.
1UPDATE
2    `users`
3SET
4    `age`=`age`+1
5LIMIT
6    5

 

http://www.spravkaweb.ru/mysql/sql/update

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

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

        location ^~ /files/ {
            root   /path/to/server;
            autoindex    on;
            autoindex_exact_size  off;
            auth_basic "Hello, please login";
            auth_basic_user_file /usr/nginx/passwords;
            access_log   /usr/nginx/logs/files.log   download;
        }

и админовской части c дополнительным ограничением по IP:

        location ^~ /admin/ {
            fastcgi_pass unix:/home/project/server.sock;
            include  conf/fastcgi.conf;
            allow 11.11.0.0/16;
            allow 22.22.22.22;
            deny all;
            auth_basic "Hello, Admin, please login";
            auth_basic_user_file /usr/nginx/adminpassword;
            access_log   /usr/nginx/logs/admin.log  main;
        }

Добавить пользователя можно с помощью стандартной утилиты от apache:

htpasswd -b passwords NewUser NewPassword

В файле запись с зашифрованным паролем имеет вид:

NewUser:P47ghZ4kloG78: Your Can Comment Here

Защиту от перебора паролей можно организовать одновременно двумя методами, основанными на использовании iptables:

  • Блокирование IP на время, если количество запросов в секунду превышает какое-либо разумное количество
  • Вести лог неудачных попыток подбора пароля и скриптом раз в минуту проверять лог и заносить IP адреса в iptables

Для первого варианта достаточно создать правила:

iptables -A INPUT -p tcp --syn --dport 80 -i eth0 -m state --state NEW
            -m recent --name bhttp --set
iptables -A INPUT -p tcp --syn --dport 80 -i eth0 -m state --state NEW
            -m recent --name bhttp --update --seconds 120
            --hitcount 360 -j DROP
iptables -A INPUT -p tcp --syn --dport 80 -i eth0 -j ACCEPT

Можно вместо DROP использовать TARPIT, чтобы усложнить жизнь ломателям 🙂

Для второго варианта надо добавить в конфиг:

        location /401.html {
            root   /usr/nginx;
            access_log   /usr/nginx/logs/denied.log  error401;
        }

Формат error401, у меня например такой:

log_format error401  '$remote_addr - $remote_user [$time_local] '
                     '$status "$request"';

Теперь все неправильные попытки будут записываться в отдельный лог, который мы можем обрабатывать по cron-у:

*/1 * * * * root /usr/nginx/parser401.pl >/dev/null 2>&1

например, таким скриптом: parser401.pl Скрипт проверяет лог, и если обнаруживает больше 4-х попыток неправильного набора пароля, блокирует этот IP.