Limitação de recursos
Outra sugestão interessante é a de limitar a utilização dos recursos do serviço, no caso do OpenSSH isso pode ser feito através de cláusulas como MaxStartups e MaxAuthTries, que definem, respectivamente, a quantidade de instâncias não autenticadas simultâneas (por padrão são 10), e quantas tentativas sem sucesso são permitidas por usuário (por padrão são 6).
Mover o serviço para uma porta não padrão
De simples implementação, no caso do OpenSSH basta editar o arquivo sshd_config e substituir, na cláusula Port, a porta 22 por outro valor. Note que este artifício é considerado "segurança por obscuridade", ou seja, não é exatamente uma medida corretiva, apenas um paliativo, visto que os ataques, por uma questão de conveniência, tendem a buscar somente a porta padrão (22/tcp).
Outra questão é sobre a necessidade de substituir rotinas automatizadas como cópias de segurança remotas, retreinamento do usuário e uma coisa a mais para lembrar (documentar) quando da atualização do pacote, ou instalação de um novo servidor.
Por fim é preciso lembrar que alguns firewalls de empresas bloqueiam portas de serviços que não são utilizadas, o que pode ser um problema para um acesso remoto emergencial, visto que um administrador pode não conseguir alcançar sua rede, por conta de um bloqueio feito na rede onde ele está no momento que foi avisado de algum problema.
Acesso somente via chaves públicas
De fácil configuração, bastando (no OpenSSH) mudar para "no" as cláusulas PasswordAuthentication e UsePAM, além de gerar o par de chaves para os usuários e equipamentos envolvidos na autenticação (clientes e servidores).
Os principais inconvenientes ficam por conta da dificuldade de conexão via equipamento de terceiros e o treinamento dos usuários. Vale lembrar que este recurso pode não ser de uso simples em alguns clientes SSH e que outros sequer possuem esta funcionalidade.
Limitar início de conexão (SYN)
Algumas ferramentas de ataque, para ganhar eficiência, disparam várias cópias de si mesmas, sendo deste modo interessante configurar no firewall alguns limitadores. Por exemplo, usando o firewall padrão do FreeBSD, é possível criar uma regra com a cláusula "limit" associada, para informar quantas conexões simultâneas são permitidas para aquela regra, por exemplo:
ipfw add allow tcp from any to 200.XX.XX.6 22 limit src-addr 1
Quando utilizado o IPFilter (FreeBSD/NetBSD/Sun/Solaris/HP-UX), um exemplo de uso seria:
pass in quick proto tcp from any to 200.XX.XX.6 port = 22 keep limit 1
No caso do PF (OpenBSD), o exemplo abaixo poderia ser usado:
pass in quick proto tcp from any to 200.XX.XX.6 port 22 flags S/SA \
keep state (max-src-states 1)
Existe uma extensão disponível para netfilter (chamada ipt_recent) que permite configurar um período de tempo no qual uma determinada conexão pode ocorrer, por exemplo a cada 120 segundos:
iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp --dport ssh -m recent --update --seconds 120 -j DROP
iptables -A INPUT -p tcp --dport ssh --tcp-flags syn,ack,rst syn -m recent --set -j ACCEPT
Essa abordagem tem um efeito colateral positivo interessante, pois permite bloquear um ataque já no momento da varredura, que normalmente precede o ataque de força bruta do serviço SSH.
Configurar pacote knockd
O programa KNOCKD está disponível atualmente para sistemas Linux, e atua de forma a permitir que, somente após o usuário enviar uma seqüência previamente conhecida de pacotes, o programa ative um serviço pré-determinado, SSH no nosso caso. É composto de um servidor (knockd) e um cliente (knock) responsável por enviar os pacotes da maneira como o knockd espera receber.
No exemplo abaixo foi inventada uma seqüência de pacotes que indicasse, ao knockd, que ele deveria iniciar a execução do serviço SSH. O arquivo de configuração knock.conf foi configurado de maneira que, para iniciar o serviço, o programa deve receber um pacote (SYN) tcp nas portas 100 e 200 e um pacote UDP na porta 300:
[openSSH]
sequence = 100:tcp,200:tcp,300:udp seq_timeout = 5 command
= /etc/init.d/ssh start tcpflags = syn
[closeSSH]
sequence = 300:udp,200:tcp,100:tcp seq_timeout = 5 command
= /etc/init.d/ssh stop tcpflags = syn
E para finalizá-lo deve receber a seqüência inversa.
Foi então executado:
# knock sitio.org.br 100:tcp 200:tcp 300:udp
Para fechar o serviço foi executado na ordem inversa:
# knock sitio.org.br 300:udp 200:tcp 100tcp
Nos logs ficou registrado:
[2005-09-23 23:47] starting up, listening on eth0
[2005-09-23 23:47] 10.0.0.1: openSSH: Stage 1
[2005-09-23 23:47] 10.0.0.1: openSSH: Stage 2
[2005-09-23 23:47] 10.0.0.1: openSSH: Stage 3
[2005-09-23 23:47] 10.0.0.1: openSSH: OPEN SESAME
[2005-09-23 23:47] openSSH: running command: /etc/init.d/ssh start
[2005-09-24 00:00] 127.0.0.1: closeSSH: Stage 1
[2005-09-24 00:00] 127.0.0.1: closeSSH: Stage 2
[2005-09-24 00:00] 127.0.0.1: closeSSH: Stage 3
[2005-09-24 00:00] 127.0.0.1: closeSSH: OPEN SESAME
[2005-09-24 00:00] closeSSH: running command: /etc/init.d/ssh stop
Esta solução tem alguns inconvenientes, uma vez que além de tornar mais complexa a ação de login remoto, pois necessita de um passo adicional, o administrador ainda deve escolher com bastante cuidado as portas usadas na sinalização, por conta de possíveis bloqueios quando atrás de firewalls.
Outro dificultador é o fato de que em alguns ambientes o acesso à Internet se dá somente através de proxy, entre outras limitações de protocolos e portas, tornando ainda mais complicado o envio de uma seqüência, de pacotes, para um equipamento remoto.