Passos para proteger nosso VPS

Este tutorial mostra como preparar e proteger um Servidor Privado Virtual (VPS) com Debian GNU / Linux. Antes de começar, algumas coisas são assumidas:

  1. Você tem um nível intermediário de familiaridade com GNU / Linux.
  2. Existe um VPS para uso pessoal ao qual temos acesso via SSH.
  3. O VPS tem o ipv4 externo dedicado 250.250.250.155 e nosso provedor possui o bloco 250.250.0.0/16. (1)
  4. Em nosso VPS teremos apenas os serviços http, https e ssh habilitados para acesso externo.
  5. O DNS externo não será habilitado, pois geralmente é feito no painel do nosso provedor. (2)
  6. Ele funcionará como superusuário.

instalação

Como primeira etapa, vamos atualizar o servidor e instalar alguns pacotes de que precisaremos:

# aptitude update & aptitude safe-upgrade # aptitude -RvW install dropbear gesftpserver sslh iptables-persistent ulogd fail2ban nginx-light apache2-utils dnsutils telnet ghostscript poppler-utils zip unzip unrar-free p7zip-full menos multitail tee mc

configuração

Agora vamos criar um usuário de trabalho. Trabalhar como root em um servidor não é seguro, portanto, primeiro criaremos um usuário especial:

operador adduser usermod -aG sudo operator

O primeiro comando cria o usuário operador, o segundo o adiciona ao grupo sudo, que permitirá a execução de aplicativos como root.

Ajuste as permissões para superusuários

Para trabalhar regularmente, usaremos o usuário operador criado anteriormente, precisamos ajustar as opções de execução do comando como superusuário, para o qual executamos o seguinte comando:

visto

Este comando basicamente permite modificar o arquivo / etc / sudoers; em que devemos conter estas linhas:

Padrões env_reset, timestamp_timeout = 0% sudo ALL = (ALL: ALL) ALL

Na primeira linha a opção é adicionada aos valores padrão timestamp_timeout que permite definir o tempo de expiração (em minutos) da senha quando o comando sudo é executado. O padrão é 5, mas às vezes não é seguro por dois motivos:

  1. Se deixarmos inadvertidamente o nosso computador conectado antes que a senha expire, alguém poderia executar um comando como superusuário sem quaisquer restrições.
  2. Se por ignorância executarmos um aplicativo ou script que contenha código malicioso antes que a senha expire, o aplicativo poderá ter acesso ao nosso sistema como superusuário, sem nosso consentimento explícito.

Portanto, para evitar riscos, colocamos o valor em zero, ou seja, cada vez que o comando sudo for executado, a senha deverá ser digitada. Se um valor negativo for definido como -1, o efeito é que a senha nunca expira, o que produziria o resultado oposto do que desejamos.

Na segunda linha é esclarecido que o grupo sudo pode executar qualquer comando em qualquer computador, o que é normal, embora possa ser ajustado. (3) Há quem por comodidade coloca a linha da seguinte forma para não ter que digitar a senha:

% sudo ALL = (ALL: ALL) NOPASSWD: ALL

No entanto, como explicamos antes, isso é arriscado e, portanto, não é recomendado.

Desativar reinicialização

Por motivos de segurança, também desativaremos a reinicialização usando a combinação de teclas Ctrl + Alt + Del, para o qual devemos adicionar esta linha no arquivo / etc / inittab:

ca: 12345: ctrlaltdel: / bin / echo "Ctrl + Alt + Del foi desativado."

Substitua OpenSSH por DropBear

A maioria dos VPS vem com OpenSSH instalado, o que certamente é muito útil, mas a menos que precisemos explorar todas as funcionalidades do OpenSSH, existem alternativas mais leves para um VPS, como Queda de urso, que geralmente é suficiente para uso regular. No entanto, uma desvantagem deste aplicativo é que ele não vem com um servidor SFTP integrado, e é por isso que instalamos o pacote no início gesftpserver.

Para configurar o Dropbear, vamos modificar o arquivo / etc / default / dropbear para que contenha estas duas linhas:

NO_START = 0 DROPBEAR_EXTRA_ARGS = "- w -p 127.0.0.1:22 -I 1200 -m"

A primeira linha simplesmente ativa o serviço e a segunda faz várias coisas:

  1. Evite o acesso root.
  2. Coloca o serviço ouvindo na porta 22 da interface local (explicaremos o porquê mais tarde).
  3. Define o tempo de espera (20 minutos).

SSLH

A porta 22 (SSH) é bem conhecida e geralmente é uma das primeiras que os hackers tentam violar; portanto, usaremos a porta 443 (SSL). Acontece que esta porta é usada para navegação segura em HTTPS.

Por isso utilizaremos o pacote sslh, que nada mais é do que um multiplexador que analisa os pacotes que chegam na porta 443 e os roteia internamente para um serviço ou outro dependendo se o tipo de tráfego é SSH ou SSL.

SSLH não pode escutar em uma interface onde outro serviço já está escutando, motivo pelo qual fizemos anteriormente o Dropbear escutar na interface local.

Agora o que precisamos fazer é indicar para sslh a interface e a porta pela qual deve escutar e para onde redirecionar os pacotes dependendo do tipo de serviço, para isso iremos modificar o arquivo de configuração / etc / default / sslh:

DAEMON = / usr / sbin / sslh DAEMON_OPTS = "- usuário sslh --listen 250.250.250.155:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:443 --pidfile / var / run / sslh / sslh. pid "RUN = sim

Por fim, reiniciamos os serviços:

service ssh stop && service dropbear start && service sslh restart

Após o comando anterior, nossa sessão segura provavelmente será interrompida, caso em que basta fazer o login novamente, mas desta vez com o usuário profissional e usando a porta 443. Se a sessão não for interrompida, é aconselhável fechá-la e comece novamente com os valores apropriados.

Se tudo funcionar corretamente, podemos continuar trabalhando como root e, se desejarmos, desinstalar o OpenSSH:

sudo su - aptitude -r purge servidor openssh

firewalls

A próxima coisa que faremos é separar os logs do firewall em um arquivo separado /var/log/firewall.log para facilitar uma análise posterior, é por isso que instalamos o pacote ulogd na inicialização. Para isso vamos editar o arquivo /etc/logd.conf para ajustar a seção relevante:

[LOGEMU] arquivo = "/ var / log / firewall.log" sync = 1

A seguir, vamos modificar o arquivo de rotação de registro / etc / logrotate / ulogd para manter uma rotação diária (com data) e salvar salvas compactadas no diretório / var / log / ulog /:

/var/log/ulog/*.log /var/log/firewall.log {daily dateext missingok compress delaycompress sharedscripts create 640 root adm postrotate /etc/init.d/ulogd reload mv /var/log/firewall.log-* .gz / var / log / ulog / endscript}

Portanto, criaremos as regras do netfilter executando o seguinte:

IPT = $ (que iptables) IPEXT = 250.250.250.155 IPEXTBLK = 250.250.0.0 / 16 IPBCAST = 255.255.255.255 $ IPT -F $ IPT -X $ IPT -Z $ IPT -A ENTRADA -i lo -j ACEITAR $ IPT - P INPUT DROP $ IPT -P FORWARD DROP $ IPT -P SAÍDA ACEITAR $ IPT -A ENTRADA -m estado --state INVALID -j ULOG --ulog-prefixo IN_INVALID $ IPT -A INPUT -p igmp -j ULOG --ulog -prefixo IN_IGMP $ IPT -A INPUT -m pkttype --pkt-type broadcast -j ULOG --ulog-prefixo IN_BCAST $ IPT -A INPUT -m pkttype --pkt-type multicast -j ULOG --ulog-prefixo IN_MCAST $ IPT -A FORWARD -j ULOG --ulog-prefixo FORWARD $ IPT -N ICMP_IN $ IPT -A INPUT!  -i lo -p icmp -j ICMP_IN $ IPT -A ICMP_IN -p icmp -f -j ULOG --ulog-prefixo IN_ICMP_FRAGMENTED $ IPT -A ICMP_IN -p icmp -m icmp -m comprimento!  --length 28: 1322 -j ULOG --ulog-prefix IN_ICMP_INVALIDSIZE $ IPT -A ICMP_IN -p icmp -m icmp -m hashlimit --hashlimit-acima de 4 / seg --hashlimit-mode srcip --hashlimit-srcmask 24 - -hashlimit-name icmpflood -j ULOG --ulog-prefix IN_ICMP_FLOOD $ IPT -A ICMP_IN -p icmp -m icmp -m hashlimit --hashlimit-upto 64kb / min --hashlimit-mode srcip --hashlimit-srcmask 24 - hashlimit-name icmpattack -j ULOG --ulog-prefixo IN_ICMP_FLOOD $ IPT -A ICMP_IN -p icmp -m icmp -m u32!  --u32 "0x4 & 0x3fff = 0x0" -j ULOG --ulog-prefixo IN_ICMP_ATTACK $ IPT -A ICMP_IN -p icmp -m icmp!  --icmp-type echo-request -m state --state NOVO -j ULOG --ulog-prefixo IN_ICMP_INVALID $ IPT -A ICMP_IN -p icmp -m icmp --icmp-type echo-request -j ULOG --ulog- prefixo IN_ICMP $ IPT -A ICMP_IN -p icmp -m icmp --icmp-type echo-request -m limite --limit 1 / s --limit-burst 4 -j ACEITAR $ IPT -A ICMP_IN -p icmp -m icmp --icmp-type echo-reply -m limit --limit 2 / sec --limit-burst 4 -j ACEITAR $ IPT -A ICMP_IN -p icmp -m icmp --icmp-type destino-inalcançável -m limit - limite 2 / s --limit-burst 4 -j ACEITAR $ IPT -A ICMP_IN -p icmp -m icmp - tempo excedido do tipoicmp -m limite --limit 2 / sec --limit-burst 4 -j ACEITAR $ IPT -A ICMP_IN -p icmp -m icmp --icmp-type parâmetro-problema -m limite --limit 2 / seg --limit-burst 4 -j ACEITAR $ IPT -A ICMP_IN -j RETURN $ IPT -N UDP_IN $ IPT -A INPUT!  -i lo -p udp -j UDP_IN $ IPT -A UDP_IN!  -i lo!  -p udp -f -j ULOG --ulog-prefixo IN_UDP_FRAGMENTED $ IPT -A UDP_IN -p udp -m udp --sport 53 -m comprimento!  --length 28: 576 -j ULOG --ulog-prefixo IN_UDP_DNS_INVALIDSIZE $ IPT -A UDP_IN -p udp -m udp --dport 53 -m -state --state NOVO -j ULOG --ulog-prefixo IN_UDP_DNSREQUEST $ IPT - A UDP_IN -p udp -m udp --dport 53 -m -state --state NOVO -j REJEITAR --rejeitar -com a porta icmp-inacessível $ IPT -A UDP_IN -p udp -m udp!  --sport 53!  -s $ IPEXTBLK!  -d $ IPBCAST -m estado --state NOVO -j ULOG --ulog-prefixo IN_UDP $ IPT -A UDP_IN -p udp -m udp -m estado --estado ESTABELECIDO, RELACIONADO -j ACEITAR $ IPT -A UDP_IN -j RETURN $ IPT -N TCP_IN $ IPT -A INPUT!  -i lo -p tcp -j TCP_IN $ IPT -A TCP_IN!  -i lo!  -p tcp -f -j ULOG --ulog-prefixo IN_TCP_FRAGMENTED $ IPT -A TCP_IN -p tcp -m tcp --sport 53 -m estado --estado ESTABELECIDO, RELACIONADO -m comprimento!  --length 513: 1500 -j ULOG --ulog-prefixo IN_TCP_DNS_INVALIDSIZE $ IPT -A TCP_IN -p tcp -m tcp --dport 53 -m estado --state NOVO -j ULOG --ulog-prefixo IN_TCP_DNS $ IPT -A TCP_IN -p tcp -m tcp --dport 53 -m estado --state NOVO -j REJEITAR --rejeitar-com icmp-porta-inacessível $ IPT -A TCP_IN -p tcp -m tcp -m multiport!  --dports 80,443 -m state --state NOVO -j ULOG --ulog-prefix IN_TCP $ IPT -A TCP_IN -p tcp -m tcp -m multiport --dports 80,443 -m state --state NOVO -m hashlimit - hashlimit-upto 4 / sec --hashlimit-burst 16 --hashlimit-mode srcip --hashlimit-name navreq -j ACEITAR $ IPT -A TCP_IN -p tcp -m tcp -m multiport --porta 80,443 -m estado - estado ESTABELECIDO -m connlimit!  --connlimit-above 16 -j ACEITAR $ IPT -A TCP_IN -p tcp -m tcp -m multiport! 

Com a configuração anterior, nosso VPS deveria estar razoavelmente protegido, mas se desejarmos podemos protegê-lo um pouco mais, para o que podemos usar algumas regras mais avançadas.

Nem todos os VPS permitem a instalação de módulos extras para netfilter, mas um muito útil é psd, o que permite evitar varreduras de portas. Infelizmente, este módulo não é integrado ao netfilter por padrão, então é necessário instalar certos pacotes e então construir o módulo:

aptitude -RvW install iptables-dev xtables-addons-source module-assistant module-assistant --verbose --text-mode auto-install xtables-addons-source

Assim que o acima for feito, podemos adicionar uma regra como esta:

iptables -A INPUT -m psd --psd-weight-threshold 15 --psd-delay-threshold 2000 --psd-lo-port-weight 3 --psd-hi-ports-weight 1 -j ULOG --ulog- prefixo IN_PORTSCAN

A regra acima significa basicamente que criaremos um contador que será incrementado em 3 cada vez que for feita uma tentativa de acesso a uma porta inferior a 1024 e em 1 cada vez que for feita uma tentativa de acessar uma porta superior a 1023, e quando este contador atingir 15 em um período de menos de 20 segundos, os pacotes serão registrados por ulog como uma tentativa de portscan. Os pacotes ainda podem ser descartados de uma vez, mas neste caso pretendemos usar fail2ban, que iremos configurar mais tarde.

Uma vez criadas as regras, devemos tomar alguns cuidados para torná-las persistentes, caso contrário, iremos perdê-las quando o servidor for reiniciado. Existem várias maneiras de fazer isso; Neste tutorial, usaremos o pacote iptables-persistent que instalamos no início, que armazena as regras em /etc/iptables/rules.v4 y /etc/iptables/rules.v6 para ipv6.

iptables-save> /etc/iptables/rules.v4

Na verdade, embora o uso de ipv6 em Cuba ainda não seja generalizado, poderíamos muito bem criar algumas regras básicas:

IPT = $ (qual ip6tables) $ IPT -P INPUT DROP $ IPT -P FORWARD DROP $ IPT -P SAÍDA ACEITAR $ IPT -A ENTRADA -i lo -j ACEITAR $ IPT -A ENTRADA! -i lo -m state --state ESTABELECIDO, RELACIONADO -j ACEITAR IPT não definido

Essas regras também podem ser persistentes:

ip6tables-save> /etc/iptables/rules.v6

Por fim, para maior segurança, limpamos o registro do firewall e reiniciamos os serviços:

echo -n> /var/log/firewall.log serviço logrotate restart serviço ulogd restart serviço iptables-persistent restart

nginx

Usaremos o Nginx como um servidor web, porque os VPSs tendem a ter uma quantidade reduzida de RAM em comparação com um servidor real, então geralmente é uma boa ideia ter algo mais leve que o Apache.

Antes de configurar o Nginx, criaremos um certificado (sem senha) para uso em HTTPS:

cd / etc / nginx openssl genrsa -des3 -out cert.key 4096 cp -v cert.key cert.key.original openssl req -new -key cert.key -out cert.csr openssl rsa -in cert.key.original - out cert.key openssl x509 -req -days 365 -in cert.csr -signkey cert.key -out cert.crt

Feito isso, criaremos um arquivo de senha para o usuário "elusuario":

htpasswd -c .htpasswd o usuário

A seguir, vamos modificar o arquivo / etc / nginx / sites-available / default para definir as preferências padrão do site. Pode ser assim:

servidor {server_name localhost; index index.html index.htm default.html default.htm; root / var / www; localização / {# define a ordem de verificação e a página a carregar, se o URI não for encontrado try_files $ uri $ uri / /index.html; }} servidor {escute 127.0.0.1:443; server_name localhost; index index.html index.htm default.html default.htm; root / var / www; ssl on; ssl_certificate cert.crt; ssl_certificate_key cert.key; ssl_session_timeout 5m; # Habilite HTTPS apenas em TLS (mais seguro do que SSL) ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # dê preferência a cifras de alta intensidade [HIGH], # mova as cifras de intensidade média [MÉDIA] para o final da lista, # desative as cifras de baixa intensidade [LOW] (40 e 56 bits) # desative as cifras com algoritmos de exportação [EXP] # desabilita cifras nulas [eNULL], sem autenticação [aNULL], SSL (versões 2 e 3) e DSS (só permite chaves de até 1024 bits) ssl_ciphers HIGH: + MEDIUM :! LOW :! EXP: ! aNULL :! eNULL :! SSLv3 :! SSLv2 :! DSS; # Prefira os métodos de criptografia do servidor (por padrão, os do cliente são usados) ssl_prefer_server_ciphers on; localização / {# ativar autenticação auth_basic "Login"; auth_basic_user_file /etc/nginx/.htpasswd; # definir a ordem de verificação e o código da página para carregar, se o URI try_files $ uri $ uri / = 404 não encontrado; # permitir a criação de um índice para usuários autenticados autoindex on; autoindex_exact_size off; autoindex_localtime on; }}

Verificamos se a configuração está correta:

nginx -t

Por fim, reiniciamos o serviço:

reiniciar serviço nginx

Falha2Ban

Antes de começar a configurar o Fail2Ban, para maior segurança paramos o serviço e limpamos o registro:

fail2ban-client stop echo -n> /var/log/fail2ban.log

Em seguida, criamos o arquivo de configuração /etc/fail2ban/jail.local com o seguinte conteúdo personalizado:

# Arquivo de configuração personalizada /etc/fail2ban/jail.local # [DEFAULT] findtime = 43200; 12 horas bantime = 86400; Maxretria de 1 dia = 3; banimento terá efeito após a 4ª tentativa [ssh] enabled = false [nginx-auth] enabled = true filter = nginx-auth action = iptables-multiport [name = NoAuthFailures, port = "http, https"] logpath = / var / log / nginx * / * erro * .log [nginx-badbots] enabled = true filter = apache-badbots action = iptables-multiport [name = BadBots, port = "http, https"] logpath = / var / log / nginx * /*access*.log bantime = 604800; 1 semana maxretry = 0 [nginx-login] habilitado = true filter = nginx-login action = iptables-multiport [nome = NoLoginFailures, port = "http, https"] logpath = / var / log / nginx * / * access *. log bantime = 1800; 30 minutos [nginx-noscript] enabled = true action = iptables-multiport [name = NoScript, port = "http, https"] filter = nginx-noscript logpath = /var/log/nginx*/*access*.log maxretry = 0 [nginx-proxy] enabled = true action = iptables-multiport [name = NoProxy, port = "http, https"] filter = nginx-proxy logpath = /var/log/nginx*/*access*.log bantime = 604800 ; 1 semana maxretry = 0 [firewall] habilitado = true action = iptables-multiport [name = Firewall] filter = firewall logpath = /var/log/firewall.log maxretry = 0

Feito isso, criamos no diretório /etc/fail2ban/filters.d/ os seguintes arquivos:

# /etc/fail2ban/filter.d/nginx-auth.conf # Filtro de autenticação # Bloqueia IPs que falham na autenticação usando autenticação básica # [Definição] failregex = nenhum usuário / senha foi fornecido para autenticação básica. * cliente: usuário. * não foi encontrado no cliente. *: usuário. * incompatibilidade de senha. * cliente: ignoreregex =
# /etc/fail2ban/filter.d/nginx-login.conf # Filtro de login # Bloqueia IPs que falham na autenticação usando a página de login do aplicativo da web # Varre o log de acesso para HTTP 200 + POST / sessões => login com falha # [Definição ] failregex = ^ -. * POST / sessões HTTP / 1 \ .. "200 ignoreregex =
# /etc/fail2ban/filter.d/nginx-noscript.conf # Filtro Noscript # Bloqueia IPs que tentam executar scripts como .php, .pl, .exe e outros scripts engraçados. # Corresponde, por exemplo, # 192.168.1.1 - - "GET /something.php # [Definição] failregex = ^ -. * GET. * (\. Php | \ .asp | \ .exe | \ .pl | \ .cgi | \ scgi) ignoreregex =
# /etc/fail2ban/filter.d/proxy.conf # Filtro de proxy # Bloqueia IPs que tentam usar o servidor como proxy. # Corresponde, por exemplo, # 192.168.1.1 - - "GET http://www.something.com/ # [Definição] failregex = ^ -. * OBTER http. * Ignoreregex =
# /etc/fail2ban/filter.d/firewall.conf # Filtro de firewall # [Definição] failregex = ^. * IN_ (INVALID | PORTSCAN | UDP | TCP |). * SRC = . * $ ignoreregex =

Por fim, iniciamos o serviço e carregamos a configuração:

fail2ban-service -b fail2ban-client reload

Verificação

Como última etapa, podemos ver os registros com cauda -f o multicauda - seguir-todos. Na verdade, o último aplicativo oferece a vantagem de permitir que vários arquivos sejam exibidos ao mesmo tempo e fornecer realce de sintaxe básico.

Caso uma conta de email não esteja configurada no VPS, é aconselhável desabilitar uma mensagem de aviso que aparece ao iniciar o multitail, para a qual executaremos o seguinte comando:

echo "check_mail: 0"> ~ / .multitailrc

Na verdade, poderíamos muito bem fazer um alias (4) para ver os logs rapidamente com um comando curto, por exemplo, "flog":

alias flog = 'multitail --follow-all /var/log/firewall.log /var/log/fail2ban.log'

1) São valores fictícios.
2) Ativar outros serviços é fácil, uma vez que você entende como funciona.
3) Para obter mais detalhes, execute man sudoers.
4) Opcionalmente, pode ser adicionado ao arquivo ~ / .bash_aliases


Deixe um comentário

Seu endereço de email não será publicado. Campos obrigatórios são marcados com *

*

*

  1. Responsável pelos dados: Miguel Ángel Gatón
  2. Finalidade dos dados: Controle de SPAM, gerenciamento de comentários.
  3. Legitimação: Seu consentimento
  4. Comunicação de dados: Os dados não serão comunicados a terceiros, exceto por obrigação legal.
  5. Armazenamento de dados: banco de dados hospedado pela Occentus Networks (UE)
  6. Direitos: A qualquer momento você pode limitar, recuperar e excluir suas informações.

  1.   msx dito

    Existem algumas coisas interessantes, +1

  2.   yukiteru dito

    @Hugo esta linha na configuração:

    ssl_protocols SSLv3 TLSv1;

    Eu removeria o SSLv3 dele porque esse protocolo não é mais seguro, mesmo no Debian Jessie, muitos serviços foram configurados para evitar o uso desse protocolo por esse motivo.

    Informações sobre o assunto aqui:

    https://www.linode.com/docs/security/security-patches/disabling-sslv3-for-poodle
    http://disablessl3.com/

    1.    Hugo dito

      A ideia não era realmente oferecer os principais serviços em HTTPS, mas explicar como usar a porta 443 para SSH sem perder a possibilidade de usá-la para HTTPS se necessário, mas obrigado pelo aviso.

      De qualquer forma, eu atualizei o artigo para modificar um pouco a configuração do nginx e, incidentalmente, incluir alguns comentários para esclarecer um pouco mais sobre os mecanismos de criptografia e para corrigir alguns pequenos erros.

  3.   Daniel PZ dito

    Muito obrigado por este ótimo tutorial, agora vou colocá-lo em prática! :D, continue assim DesdeLinux, eles sempre me surpreendem, Saudações do Peru.

  4.   Ñandekuera dito

    Muito obrigado por compartilhar.

  5.   fernando dito

    Muito bom guia e vem de pérolas agora que comecei neste blog, mas ainda mais agora que estou prestes a montar meu primeiro vps e mesmo com muitos problemas mas este artigo me tirou de muitas dúvidas, obrigado e saudações