ROS Blog Safely programming
Содержание
Безопасное программирование
Наиболее рапространённые ошибки при программировании:
Большинство ошибок при программировании, приводящих к уязвимостям в безопасности системы, связаны с предположениями о вероятном поведении кода или данных. Надеемся, что после прочтения этой краткой статьи вы будете более осторожны.
Буферы
Одной из самых распространённых атак является переполнение буфера. Если вы устанавливаете определённую фиксированную длину буфера, а злоумышленнику каким-либо образом удалось вставить в него большее количество данных, то такой код уязвим, т.е.:
char buff[10]; strcpy(buff, user_supplied_data);
Вычисление размера буфера
- Может ли атака вызвать появление в буфере паразитных нулей, что приведет к тому, что strlen выдаст неверное значение?
- Помните: strlen возвращает длину строки без терминального нуля в size_t.
- Помните: sizeof возвращает длину буфера в байтах.
Не полагайтесь на размеры.
Определение длины
Различные функции определяют длину различными способами (в этом примере n это число байт, заданное в аргументах), например:
- strncat добавляет до n байт и присоединяет нуль.
- snprintf добавляет до n-1 байт и присоединяет нуль.
- strncpy обнуляет все байты, а затем добавляет до n байт.
Проверьте описания функций!
Ошибка на единицу
Крайне распространённая ошибка, возникает тогда, когда программист запутался между размером буфера, размером данных и отсчётом от нуля.
- Буфер с размером n имеет индекс от 0 до n-1:
char buffer[10]; buffer[10] = 0x61; /* выход за пределы буфера! */
- Буфер с размером n имеет n-1 свободного места для данных:
char buffer[10]; strcpy(buffer, "EXPLOIT123"); /* теперь буфер не нуль-терминирован */
Буфер с размером MAX_PATH может сохранить MAX_PATH-1 символов.
Управляющие символы
Может ли злоумышленник вставить подстановочные символы в обрабатываемые данные? Наиболее распространёнными примерами являются '\n' '%s' '%i' и '\0'.
Обход каталогов
При соединении строк обязательно избавляйтесь от '../' '..\\':
buffer1 = "C:\\SomeDirectory\\Somewhere\\"; buffer2 = "..\\..\\ReactOS\\System32\\"; strcat(buffer1, buffer2); /* Теперь buffer1 = "C:\\SomeDirectory\\Somewhere\\..\\..\\ReactOS\\System32\\" = "C:\\ReactOS\\System32\\" */
Форматируемая строка
Это такая строка, где первый параметр (формат) printf-подобной функции задаётся пользователем.
printf(foo); */ неверно */ printf("%s", foo); */ верно */
Длины
При подсчёте длин, их значения должны быть беззнаковыми (unsigned int, а не int). Беззнаковые числа могут привести к переполнению и переходу через ноль. Числа со знаком могут быть переполнены так, что приобретут отрицательное значение. Распространённая ошибка, которая создаст проблемы при использовании переменных со знаком:
if (length < maxlength) {...}
Отрицательная длина, переданная 'безопасной' строковой функции (strncpy) обычно отменяет проверку.
Данные из сети
Данные, полученные из сети, обычно должны быть прочитаны в байтовые массивы, а не в символьные. Символы по умолчанию имеют знак, а это не то, чего хотелось бы.
Вызовы функций
Работа далеко не всех функций заканчивается успешно, проверяйте значения, возвращаемые вашими функцииями! (Это делается во всей кодовой базе).
Файлы
- Если вы хотите открыть файл, на который впоследствии будете полагаться, откройте его с эксклюзивными флагами.