Nginx – Implantação e hardening do nginx no Debian

nginx
O Nginx ( pronuncia-se “engine-x”) é um webserver e proxy reverso para os protocolos http, smtp, pop3 e imap focado em alta performance. Sua utilização vêm crescendo bastante rapidamente, numa pesquisa realizada em janeiro deste ano pela Netcraft ele ocupa o 2o. lugar entre os servidores webs ativos na internet.

Neste post apresentarei como configurar o Nginx com suporte ao PHP e todos os ajustes de segurança necessários.

NOTA: Informações importantes encontram-se nos comentários dos arquivos de configuração.

Para obter as versões mais recente usaremos os pacotes disponíveis no repositório squeeze-backports

deb http://backports.debian.org/debian-backports squeeze-backports main

aptitude install -t squeeze-backports nginx spawn-fcgi php5-cgi

Configurando o vhost

vim /etc/nginx/sites-available/www.acme.com

#O dominio acme.com é um alias para www.acme.com

server {
server_name www.acme.com acme.com;
access_log /var/log/nginx/www.acme.com.access.log;
error_log /var/log/nginx/www.acme.com.error.log;
root /var/www/acme/;

location / {
index index.php;
}

#Restrigindo o acesso ao ambiente administrativo

location /admin {
root /var/www/acme/;
index index.php;
allow 200.222.222.222;
deny all;
}

#Negando o acesso a alguns arquivos

location =/*.txt {
deny all;
log_not_found off;
access_log off;
}

location =/xmlrpc.php{
deny all;
log_not_found off;
access_log off;
}

location =/readme.html {
deny all;
log_not_found off;
access_log off;
}

#Habilitando o suporte ao PHP

location ~ .php$ {
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/var/run/php-fastcgi/php-fastcgi.socket;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/acme$fastcgi_script_name;
}
}

Hardening do Nginx

user www-data;

#Total de threads. Configure de acordo com a quantidade de CPU existente, acima de 2 CPUs = 4.
worker_processes 4;
pid /var/run/nginx.pid;

events {
#Juntamente com o work_processes permite calcular o máx. de clientes ( max clients = worker_processes * worker_connections )
worker_connections 1024;

}

http {
include /etc/nginx/mime.types;
access_log /var/log/nginx/access.log;
sendfile on;

tcp_nodelay on;

gzip on;
gzip_disable “MSIE [1-6].(?!.*SV1)”;

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

# Protecao contra DoS
client_body_buffer_size 1K;
client_header_buffer_size 1k;
client_max_body_size 2M;
large_client_header_buffers 2 1k;
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 5 5;
send_timeout 10;

# Oculta banner
server_tokens off;
}

# Limita o maximo de conexoes concorrentes por IP
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 10;

Script de inicialização do PHP-Fastcgi

vim /etc/init.d/php-fastcgi

RETVAL=0
case “$1” in
start)
$PHP_SCRIPT
RETVAL=$?
;;
stop)
killall php5-cgi
RETVAL=$?
;;
restart)
killall php5-cgi
$PHP_SCRIPT
RETVAL=$?
;;
*)
echo “Usage: php-fastcgi {start|stop|restart}”
exit 1
;;
esac
exit $RETVAL

Adicionando nos Runlevels

update-rc.d php-fastcgi defaults

Habilitando o vhost e iniciando os serviços

cd /etc/nginx/sites-enabled

ln -s ../sites-available/www.acme.com

invoke-rc.d nginx start && invoke-rc.d php-fastcgi start

UPDATE 21/03/2012

Dicas adicionais do Jeronimo Zucco (@jczucco)

#Para evitar conexões DAV (PROPFIND TRACE PROPPATCH MKCOL COPY MOVE LOCK UNLOCK OPTIONS) se isso não for utilizado, é claro.

proxy_cache_methods GET HEAD POST;

#Para acompanhar a performance e utilização do nginx, afinal a disponibilidade também é importante. Pode ser feito gráfico do rrdtool usando essa ferramenta:http://blog.kovyrin.net/2006/04/29/monitoring-nginx-with-rrdtool/

HttpStubStatusModule

Configuração do limits.conf do parâmetro “nofile” para o usuário que está rodando o nginx. Por padrão o valor é 1024 arquivos abertos, se isso for insuficiente, o log irá apresentar: “failed (24: Too many open files)”, causando negação de serviço.

#Alguns bloqueios por extensão:

location ~ /.ht {
deny all;
}
location ^/MSOffice {
deny all;
}

location ~ _vti_bin {
deny all;
}

location ~* .(dll|cmd|src)$ {
deny all;
}

#Se o nginx for proxy reverso de HTTPS, habilitar somente criptografia forte para evitar o BEAST attack (CVE-2011-3389):

ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers RC4:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

UPDATE 2 – 22/03/2012

Mais dicas do meu amigoJeronimo Zucco (@jczucco)

#Regra para evitar acidentes de “desenvolvedores” que esquecem arquivos em diretórios expostos para a internet, como dump de base de dados, código fonte backup, etc:

location ~* .(ant|asa|asax|ascx|axd|backup|bak|bat|bkp|cdx|cer|cfg|cmd|com|config|conf|cs|csproj|csr|dat|db|dbf|dll|dos|htr|htw|ida|idc|idq|inc|ini|key|licx|lnk|log|mdb|old|pass|pdb|pol|printer|pwd|resources|resx|sql|src|sys|vb|vbs|vbproj|vsdisco|webinfo|xsd|xsx)$ {
deny all;
}

#Bloqueio por hostname do que está sendo feito proxy, para evitar que uma configuração mal feita acabe abrindo o proxy para o mundo externo:

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

Considerações finais

As melhores práticas de segurança do PHP já foram abordadas nos posts anteriores [1] [2]

Como pudemos constatar sua implementação é aparentemente fácil, o site do projeto é bastante rico em documentação.

O Nginx é muito utilizado como proxy reverso tornando-se um frontend para balanceamento de carga suportando diversos protocolos, existe também um módulo de WAF chamado Naxsi, esta e outras soluções serão tratadas nos próximos posts.

Referências

Nginx and PHP-FastCGI on Debian 5

Top 20 Nginx WebServer Best Security Practices

Author: alexos

Comments

  1. Muito bom to implementando aqui no trabalho, quando comecei a pesquisar encontrei esse tutorial fantástico, ia usar o varnish mas desisti dele.

    Parabéns “case of sucess”

  2. Grande Alexos, valeu pelo post.

    Para contribuir, segue mais alguns parâmetros no nginx para hardening:

    – proxy_cache_methods GET HEAD POST; – para evitar conexões DAV (PROPFIND TRACE PROPPATCH MKCOL COPY MOVE LOCK UNLOCK OPTIONS) se isso não for utilizado, é claro.

    – HttpStubStatusModule – Para acompanhar a performance e utilização do nginx, afinal a disponibilidade também é importante. Pode ser feito gráfico do rrdtool usando essa ferramenta:http://blog.kovyrin.net/2006/04/29/monitoring-nginx-with-rrdtool/

    – Configuração do limits.conf do parãmetro “nofile” para o usuário que está rodando o nginx. Por padrão o valor é 1024 arquivos abertos, se isso for insuficiente, o log irá apresentar: “failed (24: Too many open files)”, causando negação de serviço.

    – Alguns bloqueios por extensão:

    location ~ /.ht {
    deny all;
    }
    location ^/MSOffice {
    deny all;
    }

    location ~ _vti_bin {
    deny all;
    }

    location ~* .(dll|cmd|src)$ {
    deny all;
    }

    – Se o nginx for proxy reverso de HTTPS, habilitar somente criptografia forte para evitar o BEAST attack (CVE-2011-3389):

    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers RC4:HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    Por enquanto é isso. 🙂

  3. Eta, tem mais… 🙂

    – Juntei numa regra algumas extensões que são recomendáveis serem bloqueadas. Algumas eu peguei nas regras do modsecurity, outras eu coloquei. Isso é mais para evitar acidentes de “desenvolvedores” que esquecem arquivos em diretórios expostos para a internet, como dump de base de dados, código fonte backup, etc:

    location ~* .(ant|asa|asax|ascx|axd|backup|bak|bat|bkp|cdx|cer|cfg|cmd|com|config|conf|cs|csproj|csr|dat|db|dbf|dll|dos|htr|htw|ida|idc|idq|inc|ini|key|licx|lnk|log|mdb|old|pass|pdb|pol|printer|pwd|resources|resx|sql|src|sys|vb|vbs|vbproj|vsdisco|webinfo|xsd|xsx)$ {
    deny all;
    }

    – Bloqueio por hostname do que está sendo feito proxy, para evitar que uma configuração mal feita acabe abrindo o proxy para o mundo externo:

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

    Abraço !

  4. Parabéns pelo texto! Estou começando a mexer nele, achei bem interessante.

    Achei um possível problema, se eu estiver falando besteira, me fala.

    As sintaxes abaixo:

    # Limita o maximo de conexoes concorrentes por IP
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    limit_conn addr 10;

    Pela sua descrição, ficaria fora da sessão “Server”, acho que ideal seria descrever ela antes do fechamento da sessão, certo? Veja no seu texto como colocou.

Comments are closed.