Pergunta

"O homem médio não quero ser livre.Ele simplesmente quer ser seguro." - H.L.Menken

Eu estou tentando escrever muito seguro C.Abaixo vou listar algumas das técnicas que eu uso e pedir que eles são tão segura como eu acho que eles são.Por favor, não hesite em rasgar meu código/preconceitos de calçados.Qualquer resposta que se encontra mesmo o mais trivial vulnerabilidade ou me ensina uma nova idéia será altamente valorizada.

A leitura de um fluxo:

De acordo com o GNU C Programação Tutorial getline:

A função getline vai aumentar automaticamente o bloco de memória conforme necessário, através do realloc a função, portanto, nunca há uma escassez de espaço -- uma das razões por que é getline tão seguro.[..] Observe que getline pode controlar com segurança a sua linha de entrada, não importa o tempo que for.

Eu suponho que getline deve, em todas as entradas, impedir que um estouro de buffer ocorra durante a leitura de um fluxo.

  • É minha suposição é correta?Há entradas e/ou atribuição de acções em que isso pode levar a um exploit?Por exemplo, se o primeiro caractere da sequência de algumas bizarro caractere de controle, talvez 0x08 BACKSPACE (ctl-H).
  • Tem algum trabalho foi feito para provar matematicamente getline tão seguro?

Malloc Retorna Null em caso de Falha:

Se malloc encontra um erro malloc retorna um ponteiro NULO.Isto apresenta um risco de segurança, pois não se pode ainda aplicar a aritmética do ponteiro para um valor NULO (0 x 0) ponteiro, assim wikipédia recomenda

/* Allocate space for an array with ten elements of type int. */
int *ptr = (int*)malloc(10 * sizeof (int));
if (ptr == NULL) {
    /* Memory could not be allocated, the program should handle 
       the error here as appropriate. */
} 

Seguro sscanf:

Quando utilizar sscanf Tive o hábito de atribuir o tamanho a ser extraído seqüências de caracteres para o tamanho da seqüência de caracteres de entrada esperamos evitar a possibilidade de uma sobrecarga.Por exemplo:

const char *inputStr = "a01234b4567c";
const char *formatStr = "a%[0-9]b%[0-9]c":
char *str1[strlen(inputStr)];
char *str2[strlen(inputStr)];

sscanf(inputStr, formatStr, str1, str2);

Porque str1 e str2 são o tamanho da inputStr e não mais caracteres do que strlen(inputStr) pode ser lida a partir de inputStr, parece impossível, dado todos os valores possíveis para o inputStr para causar um estouro de buffer?

  • Estou correto?Existem estranhos casos de canto que eu não tenha pensado?
  • Existem maneiras melhores de escrever isto?Bibliotecas que já resolveu?

Perguntas Gerais:

Enquanto eu postei um grande número de perguntas que eu não esperava que alguém responder a todas.As perguntas são mais de orientação para o tipo de resposta que eu estou procurando.Eu realmente quero aprender o seguro C mentalidade.

  • Que outras seguro C expressões idiomáticas estão lá fora?
  • O que canto casos eu preciso sempre verifique?
  • Como posso escrever testes de unidade para impor essas regras?
  • Como posso impor restrições em um teste ou comprovadamente maneira correta?
  • Qualquer recomendado estático/dinâmico de análise de técnicas ou ferramentas para a C?
  • O que segura C práticas de fazer você seguir e como você se justificar para si mesmo e para os outros?

Recursos:

Muitos dos recursos foram emprestados das respostas.

Foi útil?

Solução

  1. A leitura de um fluxo

O fato de que getline() "vai aumentar automaticamente o bloco de memória conforme necessário" significa que este pode ser usado como um ataque de negação de serviço ataque, como seria trivial para gerar uma entrada que foi de tanto tempo ele iria esgotar a memória disponível para o processo (ou, pior ainda, o sistema!).Uma vez que uma condição de memória ocorre, outras vulnerabilidades podem também entram em jogo.O comportamento do código em pouca/nenhuma memória raramente é bom, e é muito difícil prever.IMHO é mais seguro razoáveis limites superiores em tudo, especialmente em segurança de aplicações sensíveis.

Além disso (como você antecipar ao mencionar os caracteres especiais) getline() só dá você um buffer;não faz qualquer garantia sobre o conteúdo do buffer (como a segurança é inteiramente dependente da aplicação).Portanto, a higienização, a entrada ainda é uma parte essencial de processamento e validação de dados do usuário.

  1. sscanf

Eu tendem a preferir usar uma biblioteca de expressões regulares, e têm muito estritamente definido regexps para os dados do utilizador, em vez de usar sscanf.Desta forma, você pode executar uma boa dose de validação, no momento da entrada.

  1. Comentários gerais

    • Ferramentas de difusão estão disponíveis, o que gera aleatória de entrada (válidos e inválidos) que pode ser usado para testar o seu tratamento de entrada
    • Gerenciamento de Buffer é fundamental:estouros de buffer, fluxos de fundo, de falta de memória
    • Condições de corrida pode ser explorada em caso contrário código de segurança
    • Arquivos binários poderiam ser manipulados para injetar valores inválidos ou valores muito grandes em cabeçalhos, para formato de arquivo de código deve ser sólido e não suponha que os dados binários é válido
    • Arquivos temporários geralmente pode ser uma fonte de problemas de segurança, e deve ser cuidadosamente gerenciado
    • A injeção de código pode ser usado para substituir o sistema ou biblioteca de tempo de execução de chamadas mal-intencionadas versões
    • Plugins fornecer um grande vetor para o ataque
    • Como princípio geral, eu gostaria de sugerir ter claramente definidas as interfaces onde os dados do usuário (ou quaisquer dados de fora do aplicativo) é assumido como inválido e hostil, até que seja processada, higienizada e validados, e a única forma de dados do utilizador para introduzir o aplicativo

Outras dicas

Eu acho que seu exemplo sscanf está errado. Ainda pode transbordar quando usado dessa maneira.

Tente isso, que especifica o número máximo de bytes para ler:

void main(int argc, char **argv)
{
  char buf[256];
  sscanf(argv[0], "%255s", &buf);
}

Dê uma olhada neste artigo do IBM Dev sobre como proteger contra transbordamentos de buffer.

Em termos de teste, eu escrevia um programa que gera seqüências aleatórias de comprimento aleatório e as alimentava ao seu programa e garantiria que elas sejam tratadas adequadamente.

Um bom lugar para começar a olhar para isso é O excelente site de codificação seguro de David Wheeler.

Seu livro online gratuito "Programação segura para Linux e Unix Howto"É um excelente recurso que é atualizado regularmente.

Você também pode olhar para o seu excelente analisador estático Flagfinder para obter mais dicas. Mas lembre -se de que nenhuma ferramenta automatizada substitui um bom par de olhos experientes, ou como David coloca de maneira colorida ..

Qualquer ferramenta de análise estática, como Flagfinder, é apenas uma ferramenta. Nenhuma ferramenta pode substituir o pensamento humano! Resumidamente, "Um tolo com uma ferramenta ainda é um tolo". É um erro pensar que as ferramentas de análise (como o Flagfinder) substituem o treinamento e o conhecimento de segurança

Eu pessoalmente usei os recursos de David há vários anos e acho que sejam excelentes.

Yannick Moy desenvolveu um sistema de pré -condição mais fraco de Hoare/Floyd para C durante seu doutorado e Aplicou -o à biblioteca Cert Managed Strings. Ele encontrou vários insetos (veja a página 197 de suas memórias). A boa notícia é que a biblioteca está mais segura agora para seu trabalho.

Você também pode olhar para o site de Les Hatton aqui E em seu livro Mais seguro c que você pode obter da Amazon.

Não use gets() Para entrada, use fgets(). Usar fgets(), se o seu buffer for automaticamente alocado (ou seja, "na pilha"), use este idioma:

char buf[N];
...
if (fgets(buf, sizeof buf, fp) != NULL)

Isso continuará trabalhando se você decidir alterar o tamanho de buf. Eu prefiro este formulário a:

#define N whatever
char buf[N];
if (fgets(buf, N, fp) != NULL)

Porque o primeiro formulário usa buf para determinar o segundo argumento e é mais claro.


Verifique o valor de retorno de fclose().


Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top