19 смертных грехов, угрожающих безопасности программ
Шрифт:
int a, b, c;
c = a * b;
if(c < 0)
return BAD_INPUT;
Даже если на входе допустимы только положительные числа, этот код все равно пропускает некоторые переполнения. Возьмем, к примеру, выражение (2 А 30 + + 1) * 8, то есть 2 А 33 + 8. После отбрасывания битов, вышедших за пределы 32 разрядов, получается 8. Это число положительно, а ошибка тем не менее есть. Безопаснее решить эту задачу, сохранив результат умножения 32–разрядных чисел в 64–разрядном, а затем проверить, равен ли хотя бы один из старших битов единице. Это и будет свидетельством переполнения.
Когда встречается подобный код:
unsigned a, b;
if (a * b < MAX) {
}
проще
#include «limits.h»
#define MAX_A 10000
#define MAX_A 250
assert(UINT_MAX / MAX_A >= MAX_B); // проверим, что MAX_A и MAX_B
// достаточно малы
if (a < MAX_A && b < MAX_B) {
}
Если вы хотите надежно защитить свой код от переполнений целого, можете воспользоваться классом Safelnt, который написал Дэвид Лебланк (подробности в разделе «Другие ресурсы»). Но имейте в виду, что, не перехватывая исключения, возбуждаемые этим классом, вы обмениваете возможность выполнения произвольного кода на отказ от обслуживания. Вот пример использования класса Safelnt:
size_t CalcAllocSize(int HowMany, int Size, int HeaderLen)
{
try{
SafeInt<size_t> tmp(HowMany);
return tmp * Size + SafeInt<size_t>(HeaderLen);
}
catch(SafeIntException)
{
return (size_t)~0;
}
}
Целые со знаком используются в этом фрагменте только для иллюстрации; такую функцию следовало бы писать, пользуясь одним лишь типом size_t. Посмотрим, что происходит «под капотом». Прежде всего проверяется, что значение HowMany неотрицательно. Попытка присвоить отрицательное значение беззнаковой переменной типа Safelnt вызовет исключение. Затем Safelnt умножается на переменную Size типа int, при этом проверяется как переполнение, так и попадание в допустимый диапазон. Результат умножения Safelnt * int – это снова Safelnt, поэтому далее выполняется операция контролируемого сложения. Обратите внимание на приведение входного параметра типа int к типу Safelnt – отрицательная длина заголовка с точки зрения математики, может быть, и допустима, но с точки зрения здравого смысла – нет, поэтому размеры лучше представлять числами без знака. Наконец, перед возвратом величина типа Safelnt<size_t> преобразуется обратно в size_t, это пустая операция. Внутри класса Safelnt выполняется много сложных проверок, но ваш код остается простым и понятным.
Если вы программируете на С#, включайте флаг /checked и применяйте unchecked–блоки только для того, чтобы отключить контроль в отдельных предложениях.
Дополнительные защитные меры
Если вы работаете с компилятором gcc, то можете задать флаг–ftrapv. В этом случае за счет обращения к различным функциям во время выполнения будут перехватываться переполнения при операциях со знаковыми и только со знаковыми целыми. Неприятность в том, что при обнаружении переполнения вызывается функция abort.
Компилятор Microsoft Visual С++ 2005 автоматически обнаруживает переполнение при вызове оператора new. Ваша программа должна перехватывать исключения std::bad_alloc, иначе произойдет аварийный останов.
Другие
□ «Integer Handling with the С++ Safelnt Class», David LeBlanc, msdn.microsoft.com/library/default.asp?url=/library/en–us/dncode/html/ secure01142004.asp
□ «Another Look at the Safelnt Class», David LeBlanc,library/default.asp?url=/library/en–us/dncode/html/secure05052005.asp
□ «Reviewing Code for Integer Manipulation Vulnerabilities*, Michael Howard,microsoft, com/library/default.asp?url=/library/en–us/dncode/ html/ secure04102003.asp
□ «An Overlooked Construct and an Integer Overflow Redux», Michael Howard,microsoft, com/library/default.asp?url=/library/en–us/dncode/ html/ secure09112003.asp
□ «Expert Tips for Finding Security Defects in Your Code», Michael Howard,1/SecurityCodeReview/ default.aspx
□ «Integer overflows – the next big threat», Ravind Ramesh, central.com/tech/story.asp?file=/2004/10/26/itfeature/9170256&sec=itfeature
□ DOS against Java JNDI/DNS,bugtraq/2004–11 / 0092.html
Резюме
Рекомендуется
□ Проверяйте на возможность переполнения все арифметические вычисления, в результате которых определяется размер выделяемой памяти.
□ Проверяйте на возможность переполнения все арифметические вычисления, в результате которых определяются индексы массивов.
□ Пользуйтесь целыми без знака для хранения смещений от начала массива и размеров блоков выделяемой памяти.
Не рекомендуется
□ Не думайте, что ни в каких языках, кроме C/C++, переполнение целого невозможно.
Грех 4. Внедрение SQL–команд
В чем состоит грех
Уязвимость для внедрения SQL–команд (или просто «внедрение SQL») – это широко распространенный дефект, который может привести к компрометации машины и раскрытию секретных данных. А печальнее всего то, что от этой ошибки часто страдают приложения электронной коммерции и программы, обрабатывающие конфиденциальные данные и персональную информацию. Опыт авторов показывает, что многие приложения, работающие с базами данных, которые создавались для внутреннего использования или обмена информацией с партнерами по бизнесу, подвержены внедрению SQL.
Никогда не интересовались, как хакеры воруют номера кредитных карточек с Web–сайтов? Одним из двух способов: либо внедряя SQL, либо заходя через парадный вход, который вы распахиваете перед ними, открывая порт сервера базы данных (ТСР/1433 для Microsoft SQL Server, TCP/1521 для Oracle, TCP/523 для IBM/DB2 и TCP/3306 для MySQL) для доступа из Интернет и оставляя без изменения принимаемый по умолчанию пароль администратора базы данных.
Быть может, самая серьезная опасность, связанная с внедрением SQL, – это получение противником персональных или секретных данных. В некоторых странах, штатах и отраслях промышленности вас за это могут привлечь к суду. Например, в штате Калифорния можно сесть в тюрьму по закону о защите тайны личной жизни в сети, если из управляемой вами базы данных была похищена конфиденциальная или персональная информация. В Германии §9 DBSG (Федеральный закон о защите данных) требует, чтобы были предприняты должные организационные и технические меры для защиты систем, в которых хранится персональная информация. Не забывайте также о действующем в США Акте Сарбанеса–Оксли от 2002 года, и прежде всего о параграфе 404, который обязывает защищать данные, на основе которых формируется финансовая отчетность компании. Система, уязвимая для атак с внедрением SQL, очевидно, имеет неэффективные средства контроля доступа, а значит, не соответствует всем этим установлениям.