Поиск проблем безопасности в заданном коде [закрыто]

Может кто-нибудь, пожалуйста, скажите мне, как найти недостатки безопасности в данном коде. Например: в данной программе сокетов. Любые хорошие примеры или хорошие книжные рекомендации приветствуются.

Спасибо и С уважением,

Мышь

9
задан mousey 8 August 2010 в 08:54
поделиться

6 ответов

Самым слабым плодом в этой категории будет простой поиск в источнике функций, которые часто используются неправильно или которые сложно безопасно использовать, например:

  • strcpy
  • strcat
  • sprintf
  • gets

затем начните искать те, которые не так уж плохи по своей природе, но могут быть использованы неправильно. В частности, все, что записывает в буфер, может быть потенциально опасным при неправильном использовании.

  • memcpy
  • memmove
  • recv / read
  • send / write
  • все семейство printf всегда должно иметь константу для строки формата

ПРИМЕЧАНИЕ: все это (кроме gets ) можно использовать правильно, поэтому не думайте, что это недостаток только потому, что функция используется, вместо этого посмотрите, как она используется. Также обратите внимание, что получает - это всегда недостаток.

ПРИМЕЧАНИЕ2: этот список не исчерпывающий, проведите небольшое исследование о часто используемых неправильно функциях и о том, как их можно избежать.

Что касается инструментов, я рекомендую такие вещи, как valgrind и splint

4
ответ дан 3 November 2019 в 00:57
поделиться

Вот рекомендация из книги: Написание кода безопасности . Демонстрирует не только то, как писать безопасный код, но также общие подводные камни и методы, которые обнаруживают дыры в безопасности. Он немного устарел (в моей копии написано, что он был опубликован в 2002 году), но концепции безопасности, которым он учит, все еще применимы даже 8 лет спустя.

2
ответ дан 3 November 2019 в 00:57
поделиться

Некоторые представители OpenBSD недавно опубликовали презентацию о своих методах кодирования .

0
ответ дан 3 November 2019 в 00:57
поделиться

Some source code constructs you can keep an eye out for are:

  • Functions that don't do bounds checking. Evan covered it pretty well.
  • Input validation & sanitization, or lack thereof.
  • NULL pointer dereferencing
  • fork()s, execve()s, pipe()s, system() called with non-static parameters (or worse, with user input).
  • Objects shared between threads with inappropriate storage durations (pointers to automatic variables or even "dead" objects in thread-local storage).
  • When dealing with file manipulation, make sure correct variable types are used for the return results of functions. Make sure they're checked for errors. Make no assumptions about the implementation - permissions of created files, uniqueness of filenames, etc.
  • Следует избегать плохих источников случайности (для шифрования, связи и т.д.).
  • Простые или очевидные ошибки (возможно, по невнимательности) должны быть исправлены в любом случае. Вы никогда не знаете, что можно эксплуатировать, пока это не так.

Также, защищены ли данные? Ну, если вам все равно, то это прекрасно. :-)

Некоторые инструменты, которые вы можете рассмотреть:

  • valgrind : раскрывает недостатки памяти, которые в больших приложениях обычно критичны.
  • splint : статический чекер
  • fuzzing фреймворки
  • RATS : бесплатный инструмент с открытым исходным кодом. Компания его авторов была приобретена Fortify.
1
ответ дан 3 November 2019 в 00:57
поделиться

Одна из основных тем, которая не была затронута в ответе Эвана, - это целочисленные переполнения. Вот несколько примеров:

wchar_t *towcs(const char *s)
{
    size_t l = strlen(s)+1;
    mbstate_t mbs = {0};
    wchar_t *w = malloc(l*sizeof *w), *w2;
    if (!w || (l=mbsrtowcs(w, (char **)&s, l, &st))==-1) {
        free(w);
        return 0;
    }
    return (w2=realloc(w, l*sizeof *w)) ? w2 : w;
}

Здесь гигантская строка (> 1 гигабайта на 32-битной) произведет умножение на размер (я предполагаю, что 4) переполнение, что приведет к крошечному выделению и последующим операциям записи после его конца.

Другой более распространенный пример:

uint32_t cnt;
fread(&cnt, 1, 4, f);
cnt=ntohl(cnt);
struct record *buf = malloc(cnt * sizeof *buf);

Этот вид кода довольно часто появляется при чтении файловых / сетевых данных и подвержен таким же переполнениям.

По сути, любые арифметические операции, выполняемые со значениями, полученными из ненадежного источника, которые в конечном итоге будут использоваться в качестве размера выделения / смещения массива, должны быть проверены. Вы можете сделать это дешевым способом (наложить произвольные ограничения на считываемое значение, чтобы оно значительно выходило за пределы диапазона, который может переполниться, либо вы можете проверять переполнение на каждом шаге: Вместо:

foo = malloc((x+1)*sizeof *foo);

Вам необходимо сделать:

if (x<=SIZE_MAX-1 && x+1<=SIZE_MAX/sizeof *foo) foo = malloc((x+1)*sizeof *foo);
else goto error;

Простая команда grep для malloc / realloc с арифметическими операторами в аргументе обнаружит много таких ошибок (но не тех, где переполнение уже произошло несколькими строками выше и т. Д.).

4
ответ дан 3 November 2019 в 00:57
поделиться

Я посещал занятия по безопасности, где мы использовали коммерческий продукт под названием Fortify 360, который делал статический анализ кода C++. Мы проверили его на старой-старой версии OpenSSL, и он нашел кучу всего, а также предоставил руководство по устранению недостатков (которые, кстати, в последней версии OpenSSL были устранены).

В любом случае, это полезный коммерческий инструмент.

0
ответ дан 3 November 2019 в 00:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: