Artigo faz parte da disciplina de "Segurança de Sistemas", do professor
Elgio Schlemer.
Muitos programadores, pensam apenas em ataques que podem ser feitos apenas na maquina que esta rodando o programa, e acabam não se preocupando com a segurança de seu próprio programa. Existem muitas vulnerabilidades conhecidas em C que podem ser evitadas introduzindo boas praticas para se fazer uma programação segura.
Inúmeras formas podem ser adotadas para se proteger o programa. A inicialização segura de um programa é muito importante, pois muitos ataques podem ser feitos simplesmente na hora da inicialização de seu programa. Algumas vulnerabilidades na inicialização do seu programa e soluções para as mesmas serão descritas neste artigo.
Outro ponto importante para segurança do seu programa é o controle de acesso em pastas e/ou arquivos utilizados pelo programa, que também será abordado no artigo. Um ataque pode ser feito simplesmente porque o programador se descuidou na hora de fazer validações em um campo de entrada de texto. Algumas boas práticas sobre a segurança do programa, serão demonstradas neste artigo.
Inicializando seu programa com segurança
Descritor de arquivo
Uma potencial vulnerabilidade em seu código C, pode ser um deny of service, gerado por arquivos desnecessários preenchendo o descritor de arquivo até seu limite. Quando um processo é iniciado, ele herda todos os descritores de arquivo de seu processo pai, como no Unix o descritor de arquivo tem um tamanho fixo, esta herança de descritores abertos pode preencher todo o tamanho da tabela do descritor com arquivos lixo causando uma negação de serviço em seu programa.
Para se defender do problema de negação de serviço causado pelo descritor de arquivo cheio, devemos sempre que iniciar o programa fechar todos os descritores que não são os descritores default (stdin, stdout, stderr) e se certificar que os defaults estão abertos.
Matt Messier e
John Viega (2008, sessão 1.5) dizem que no Windows, não tem como verificar quais arquivos estão abertos, mas o mesmo problema não está presente no Windows.
Mantendo os dados do programa seguro depois de uma falha de sistema
Imagine se um programa que necessita armazenar dados de números de cartão de crédito no disco para utiliza-lo? Se por um acaso o programa falhe ou tranque, os dados não podem em hipótese alguma estar disponíveis depois da falha, pois pessoas com más intenções podem examinar os dados e usa-los.
Na maioria dos sistema Unix, quando o programa termina devido a uma falha de sistema, o sistema terá um despejo de memória. O problema deste despejo de memória, é que ele pode conter dados confidenciais e que podem ser usados por atackers.
Nos sistemas unix, podemos limitar o despejo de memória usando a função setrlimit( ) para setar o RLIMIT_CORE para zero. Sem esta limitação, um atacker, pode descobrir uma maneira de quebrar o sistema e causar um despejo de memória preenchendo todo o espaço em disco. Setando o valor de RLIMIT_CORE para 0, previne o sistema de preencher despejos de memória e ao invés disto ele apenas fecha o programa.
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
void spc_limit_core(void) {
struct rlimit rlim;
rlim.rlim_cur = rlim.rlim_max = 0;
setrlimit(RLIMIT_CORE, &rlim);
}