Nginx Web Server (Security)

Nginx — веб-сервер и почтовый прокси-сервер.

Nginx - один из немногих серверов, написанный для решения проблемы C10K. В отличие от традиционных серверов, Nginx не полагается на потоки для обработки запросов. Вместо этого он использует гораздо более масштабируемую (асинхронную) архитектуру. Nginx поддерживает работу нескольких сайтов с высоким трафиком, таких как WordPress, Hulu, Github и SourceForge.

Включение SELinux. Security-Enhanced Linux (SELinux) - это функция ядра Linux, обеспечивающая механизм поддержки политик безопасности контроля доступа, который обеспечивает отличную защиту. Она может остановить множество атак. Запустите getebool - систему команд и блокировки:

getsebool -a | less

getsebool -a | grep off

getsebool -a | grep on

Чтобы обезопасить машину, посмотрите на настройки, которые установлены в 'on' и измените их на 'off', если они не применимы к вашей установке с помощью команды setebool. Установите правильные SE Linux booleans для поддержания функциональности и защиты. Обратите внимание, что SELinux добавляет 2-8% накладных расходов к обычной установке RHEL или CentOS.

Разрешить минимальные привилегии через опции. Сервер хранения всех ваших веб-страниц / html / php файлов через отдельные разделы. Например, создайте раздел под названием /dev/sda5 и смонтируйте его в /nginx. Убедитесь, что /nginx смонтирован с разрешениями noexec, nodev и nosetuid. Запись в /etc/fstab для монтирования /nginx:

LABEL=/nginx /nginx   ext3   defaults,nosuid,noexec,nodev 1 2

Обратите внимание, что вам нужно создать новый раздел, используя команды fdisk и mkfs.ext3.

Вы можете управлять и настраивать ядро Linux и сетевые параметры через /etc/sysctl.conf.

# Avoid a smurf attack

net.ipv4.icmp_echo_ignore_broadcasts = 1

  # Turn on protection for bad icmp error messages

net.ipv4.icmp_ignore_bogus_error_responses = 1

  # Turn on syncookies for SYN flood attack protection

net.ipv4.tcp_syncookies = 1   # Turn on and log spoofed, source routed, and redirect packets

net.ipv4.conf.all.log_martians = 1

net.ipv4.conf.default.log_martians = 1   # No source routed packets here

net.ipv4.conf.all.accept_source_route = 0

net.ipv4.conf.default.accept_source_route = 0   # Turn on reverse path filtering

net.ipv4.conf.all.rp_filter = 1

net.ipv4.conf.default.rp_filter = 1

  # Make sure no one can alter the routing tables

net.ipv4.conf.all.accept_redirects = 0

net.ipv4.conf.default.accept_redirects = 0

net.ipv4.conf.all.secure_redirects = 0

net.ipv4.conf.default.secure_redirects = 0   # Don't act as a router

net.ipv4.ip_forward = 0

net.ipv4.conf.all.send_redirects = 0

net.ipv4.conf.default.send_redirects = 0     # Turn on execshild

kernel.exec-shield = 1

kernel.randomize_va_space = 1   # Tuen IPv6

net.ipv6.conf.default.router_solicitations = 0

net.ipv6.conf.default.accept_ra_rtr_pref = 0

net.ipv6.conf.default.accept_ra_pinfo = 0

net.ipv6.conf.default.accept_ra_defrtr = 0

net.ipv6.conf.default.autoconf = 0

net.ipv6.conf.default.dad_transmits = 0

net.ipv6.conf.default.max_addresses = 1   # Optimization for port usefor LBs

# Increase system file descriptor limit

fs.file-max = 65535   # Allow for more PIDs (to reduce rollover problems); may break some programs 32768

kernel.pid_max = 65536   # Increase system IP port limits

net.ipv4.ip_local_port_range = 2000 65000   # Increase TCP max buffer size setable using setsockopt()

net.ipv4.tcp_rmem = 4096 87380 8388608

net.ipv4.tcp_wmem = 4096 87380 8388608   # Increase Linux auto tuning TCP buffer limits

# min, default, and max number of bytes to use

# set max to at least 4MB, or higher if you use very high BDP paths

# Tcp Windows etc

net.core.rmem_max = 8388608

net.core.wmem_max = 8388608

net.core.netdev_max_backlog = 5000

net.ipv4.tcp_window_scaling = 1

Удалить все нежелательные модули Nginx. Необходимо минимизировать количество модулей, которые компилируются непосредственно в бинарный файл nginx. Это минимизирует риск, ограничивая возможности, разрешенные веб-сервером. Вы можете настроить и установить nginx, используя только необходимые модули. Например, вы можете отключить SSI и модуль автоиндексации:

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

# make

# make install

Введите следующую команду, чтобы увидеть, какие модули можно включать или выключать при компиляции сервера nginx:

# ./configure --help | less

Отключите модули nginx, которые вам не нужны.

Изменить заголовок версии Nginx. Отредактируйте /src/http/ngx_http_header_filter_module.c, введите:

# vi +48 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: Ninja Web Server" CRLF;

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

Теперь вы можете скомпилировать сервер. Добавьте в nginx.conf следующее, чтобы отключить отображение номера версии nginx на всех страницах автоматической генерации ошибок:

server_tokens off

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

# yum -y install selinux-policy-targeted selinux-policy-devel

Скачайте с домашней страницы проекта целевые политики SELinux:

# cd /opt

# wget 'http://downloads.sourceforge.net/project/selinuxnginx/se-ngix_1_0_10.ta…'

 

# tar -zxvf se-ngix_1_0_10.tar.gz

 

# cd se-ngix_1_0_10/nginx

# make 

Compiling targeted nginx module

/usr/bin/checkmodule:  loading policy configuration from tmp/nginx.tmp

/usr/bin/checkmodule:  policy configuration loaded

/usr/bin/checkmodule:  writing binary representation (version 6) to tmp/nginx.mod

Creating targeted nginx.pp policy package

rm tmp/nginx.mod.fc tmp/nginx.mod

Установите модуль nginx.pp SELinux:

# /usr/sbin/semodule -i nginx.pp

Брандмауэр на базе Iptables. Следующий скрипт брандмауэра блокирует все что можно и только позволяет главное:

  • Incoming HTTP (TCP port 80) requests.
  • Incoming ICMP ping requests.
  • Outgoing ntp (port 123) requests.
  • Outgoing smtp (TCP port 25) requests.
#!/bin/bash

IPT="/sbin/iptables"
 
#### IPS ######

# Get server public ip

SERVER_IP=$(ifconfig eth0 | grep 'inet addr:' | awk -F'inet addr:' '{ print $2}' | awk '{ print $1}')

LB1_IP="204.54.1.1"

LB2_IP="204.54.1.2"

 
# Do some smart logic so that we can use damm script on LB2 too

OTHER_LB=""

SERVER_IP=""

[[ "$SERVER_IP" == "$LB1_IP" ]] && OTHER_LB="$LB2_IP" || OTHER_LB="$LB1_IP"

[[ "$OTHER_LB" == "$LB2_IP" ]] && OPP_LB="$LB1_IP" || OPP_LB="$LB2_IP"
 
### IPs ###

PUB_SSH_ONLY="122.xx.yy.zz/29"
 
#### FILES #####

BLOCKED_IP_TDB=/root/.fw/blocked.ip.txt

SPOOFIP="127.0.0.0/8 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 169.254.0.0/16 0.0.0.0/8 240.0.0.0/4 255.255.255.255/32 168.254.0.0/16 224.0.0.0/4 240.0.0.0/5 248.0.0.0/5 192.0.2.0/24"

BADIPS=$( [[ -f ${BLOCKED_IP_TDB} ]] && egrep -v "^#|^$" ${BLOCKED_IP_TDB})
 
### Interfaces ###

PUB_IF="eth0"   # public interface

LO_IF="lo"      # loopback

VPN_IF="eth1"   # vpn / private net
 
### start firewall ###

echo "Setting LB1 $(hostname) Firewall..."
 
# DROP and close everything

$IPT -P INPUT DROP

$IPT -P OUTPUT DROP

$IPT -P FORWARD DROP
 
# Unlimited lo access
$IPT -A INPUT -i ${LO_IF} -j ACCEPT

$IPT -A OUTPUT -o ${LO_IF} -j ACCEPT
 
# Unlimited vpn / pnet access

$IPT -A INPUT -i ${VPN_IF} -j ACCEPT

$IPT -A OUTPUT -o ${VPN_IF} -j ACCEPT
 
# Drop sync

$IPT -A INPUT -i ${PUB_IF} -p tcp ! --syn -m state --state NEW -j DROP
 
# Drop Fragments

$IPT -A INPUT -i ${PUB_IF} -f -j DROP
 
$IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP

$IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL ALL -j DROP
 
# Drop NULL packets

$IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL NONE -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " NULL Packets "

$IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL NONE -j DROP
 
$IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
 
# Drop XMAS

$IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags SYN,FIN SYN,FIN -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " XMAS Packets "

$IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
 
# Drop FIN packet scans

$IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags FIN,ACK FIN -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " Fin Packets Scan "

$IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags FIN,ACK FIN -j DROP
 
$IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
 
# Log and get rid of broadcast / multicast and invalid

$IPT  -A INPUT -i ${PUB_IF} -m pkttype --pkt-type broadcast -j LOG --log-prefix " Broadcast "

$IPT  -A INPUT -i ${PUB_IF} -m pkttype --pkt-type broadcast -j DROP
 
$IPT  -A INPUT -i ${PUB_IF} -m pkttype --pkt-type multicast -j LOG --log-prefix " Multicast "

$IPT  -A INPUT -i ${PUB_IF} -m pkttype --pkt-type multicast -j DROP
 
$IPT  -A INPUT -i ${PUB_IF} -m state --state INVALID -j LOG --log-prefix " Invalid "

$IPT  -A INPUT -i ${PUB_IF} -m state --state INVALID -j DROP
 
# Log and block spoofed ips

$IPT -N spooflist

for ipblock in $SPOOFIP
do
         $IPT -A spooflist -i ${PUB_IF} -s $ipblock -j LOG --log-prefix " SPOOF List Block "

         $IPT -A spooflist -i ${PUB_IF} -s $ipblock -j DROP

done

$IPT -I INPUT -j spooflist

$IPT -I OUTPUT -j spooflist

$IPT -I FORWARD -j spooflist
 
# Allow ssh only from selected public ips

for ip in ${PUB_SSH_ONLY}

do

        $IPT -A INPUT -i ${PUB_IF} -s ${ip} -p tcp -d ${SERVER_IP} --destination-port 22 -j ACCEPT

        $IPT -A OUTPUT -o ${PUB_IF} -d ${ip} -p tcp -s ${SERVER_IP} --sport 22 -j ACCEPT
done
 
# allow incoming ICMP ping pong stuff

$IPT -A INPUT -i ${PUB_IF} -p icmp --icmp-type 8 -s 0/0 -m state --state NEW,ESTABLISHED,RELATED -m limit --limit 30/sec  -j ACCEPT

$IPT -A OUTPUT -o ${PUB_IF} -p icmp --icmp-type 0 -d 0/0 -m state --state ESTABLISHED,RELATED -j ACCEPT
 
# allow incoming HTTP port 80

$IPT -A INPUT -i ${PUB_IF} -p tcp -s 0/0 --sport 1024:65535 --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT

$IPT -A OUTPUT -o ${PUB_IF} -p tcp --sport 80 -d 0/0 --dport 1024:65535 -m state --state ESTABLISHED -j ACCEPT
 
 
# allow outgoing ntp

$IPT -A OUTPUT -o ${PUB_IF} -p udp --dport 123 -m state --state NEW,ESTABLISHED -j ACCEPT

$IPT -A INPUT -i ${PUB_IF} -p udp --sport 123 -m state --state ESTABLISHED -j ACCEPT
 
# allow outgoing smtp

$IPT -A OUTPUT -o ${PUB_IF} -p tcp --dport 25 -m state --state NEW,ESTABLISHED -j ACCEPT

$IPT -A INPUT -i ${PUB_IF} -p tcp --sport 25 -m state --state ESTABLISHED -j ACCEPT
 
### add your other rules here ####
 
#######################

# drop and log everything else

$IPT -A INPUT -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " DEFAULT DROP "

$IPT -A INPUT -j DROP
 
exit 0

Управление атаками на переполнение буфера. Отредактируйте nginx.conf и установите ограничения на размер буфера для всех клиентов.

# vi /usr/local/nginx/conf/nginx.conf

Отредактируйте и установите ограничения на размер буфера для всех клиентов следующим образом:

## Start: Size Limits & Buffer Overflows ##

  client_body_buffer_size  1K;

  client_header_buffer_size 1k;

  client_max_body_size 1k;

  large_client_header_buffers 2 1k;

 ## END: Size Limits & Buffer Overflows ##

Вы можете использовать модуль NginxHttpLimitZone для ограничения количества одновременных подключений для назначенного сеанса или в качестве особого случая, с одного IP-адреса. Пример nginx.conf:

### Directive describes the zone, in which the session states are stored i.e. store in slimits. ###

### 1m can handle 32000 sessions with 32 bytes/session, set to 5m x 32000 session ###

       limit_zone slimits $binary_remote_addr 5m;   ### Control maximum number of simultaneous connections for one session i.e. ###

### restricts the amount of connections from a single ip address ###

        limit_conn slimits 5;

Вышеуказанное ограничивает количество одновременно "открытых" клиентов не более чем 5-ю соединениями на один удаленный ip-адрес.

Если бот просто делает случайное сканирование сервера на все домены, просто блокируйте это. Вы должны разрешить только настроенные виртуальные домены или обратные запросы прокси. Если вы не хотите отображать запрос, используйте IP-адрес:

## Only requests to our Host are allowed i.e. wp-login.crimea-karro.ru, images.nixcraft.in and www.wp-login.crimea-karro.ru

      if ($host !~ ^(nixcraft.in|www.wp-login.crimea-karro.ru|images.wp-login.crimea-karro.ru)$ ) {

         return 444;

      }

##

GET и POST - наиболее распространенные методы в Интернете. Методы веб-сервера определены в RFC 2616. Если веб-сервер не требует реализации всех доступных методов, их следует отключить. Следующее значение будет фильтровать и разрешать только GET, HEAD и POST методы:

## Only allow these request methods ##

     if ($request_method !~ ^(GET|HEAD|POST)$ ) {

         return 444;

     }

## Do not accept DELETE, SEARCH and other methods ##

Вы можете легко заблокировать пользователей-агентов, т.е. сканеров, ботов и спамеров, которые могут злоупотреблять вашим сервером.

## Block download agents ##

     if ($http_user_agent ~* LWP::Simple|BBBike|wget) {

            return 403;

     }

##

Блочные роботы, называемые msnbot и scrapbot:

## Block some robots ##

     if ($http_user_agent ~* msnbot|scrapbot) {

            return 403;

     }

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

## Deny certain Referers ###

     if ( $http_referer ~* (babes|forsale|girl|jewelry|love|nudit|organic|poker|porn|sex|teen) )

     {

         # return 404;

         return 403;

     }

##

Hotlinking. Изображение или HTML-ссылка означает, что кто-то делает ссылку на ваш сайт на одно из ваших изображений, но отображает его на своем собственном сайте. Обычно это делается на форумах и блогах. Я настоятельно рекомендую вам заблокировать и остановить "горячую линковку" изображений на самом уровне вашего сервера.

# Stop deep linking or hot linking

location /images/ {

  valid_referers none blocked www.example.com example.com;

   if ($invalid_referer) {

     return   403;

   }

}

Другой пример со ссылкой на запрещенное изображение:

valid_referers blocked www.example.com example.com;

 if ($invalid_referer) {

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

 }

Каталог Ограничения. Вы можете установить контроль доступа к указанному каталогу. Все веб-каталоги должны быть настроены в каждом конкретном случае, разрешая доступ только в случае необходимости. Ограничение доступа по Ip-адресу. Вы можете ограничить доступ к каталогу по ip-адресу до каталога /docs/:

location /docs/ {

  ## block one workstation

  deny    192.168.1.1;

  ## allow anyone in 192.168.1.0/24

  allow   192.168.1.0/24;

  ## drop rest of the world

  deny    all;

}

Защита паролем. Сначала создайте файл паролей и добавьте пользователя vivek:

# mkdir /usr/local/nginx/conf/.htpasswd/

# htpasswd -c /usr/local/nginx/conf/.htpasswd/passwd vivek

Отредактируйте nginx.conf и защищайте необходимые каталоги следующим образом:

### Password Protect /personal-images/ and /delta/ directories ###

location ~ /(personal-images/.*|delta/.*) {

  auth_basic  "Restricted";

  auth_basic_user_file   /usr/local/nginx/conf/.htpasswd/passwd;

}

После того, как файл паролей сгенерирован, последующие пользователи могут быть добавлены следующей командой:

# htpasswd -s /usr/local/nginx/conf/.htpasswd/passwd userName

Советы по безопасности Nginx и PHP. PHP является одним из популярных скриптовых языков на стороне сервера. Отредактируйте /etc/php.ini следующим образом:

# Disallow dangerous functions

disable_functions = phpinfo, system, mail, exec
 
## Try to limit resources  ##
 
# Maximum execution time of each script, in seconds

max_execution_time = 30
 
# Maximum amount of time each script may spend parsing request data

max_input_time = 60
 
# Maximum amount of memory a script may consume (8MB)

memory_limit = 8M
 
# Maximum size of POST data that PHP will accept.

post_max_size = 8M
 
# Whether to allow HTTP file uploads.

file_uploads = Off
 
# Maximum allowed size for uploaded files.

upload_max_filesize = 2M
 
# Do not expose PHP error messages to external users

display_errors = Off
 
# Turn on safe mode

safe_mode = On
 
# Only allow access to executables in isolated directory

safe_mode_exec_dir = php-required-executables-path
 
# Limit external access to PHP environment

safe_mode_allowed_env_vars = PHP_
 
# Restrict PHP information leakage

expose_php = Off
 
# Log all errors

log_errors = On
 
# Do not register globals for input data

register_globals = Off
 
# Minimize allowable PHP post size

post_max_size = 1K
 
# Ensure PHP redirects appropriately

cgi.force_redirect = 0
 
# Disallow uploading unless necessary

file_uploads = Off
 
# Enable SQL safe mode

sql.safe_mode = On
 
# Avoid Opening remote files

allow_url_fopen = Off

Веб-сервер должен следить за соединениями и ограничивать количество соединений в секунду. Как pf, так и iptables могут дросселировать конечных пользователей перед доступом к вашему серверу nginx. Следующий пример сбросит входящие соединения, если IP сделает более 15 попыток подключения к порту 80 в течение 60 секунд:

/sbin/iptables -A INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --set

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

service iptables save


Применение nginx целесообразно прежде всего для статических веб-сайтов и как обратного прокси-сервера перед динамическими сайтами.