6. Качество ПО
• Каждому требуется своё. ПО, работающее на изолированном компьютере, и веб-сайт правительства
• Целостность
• Доступность
• С усложнением инфраструктуры усложнились требования к качеству ПО. Теперь не достаточно выполнять
свои функции правильно, необходимо учитывать возможные нападения.
• Принципиальная невозможность добиться абсолютно правильной программы: машина Тьюринга,
Microsoft.
• Целостность
• Доступность
• Конфиденциальность
7. Факторы, влияющие на уязвимость ПО
• Ошибки программирования (переполнение буфера),
• Ошибки архитектуры (хранение пароля администратора на компьютере пользователя, реализация
контроля доступа на стороне клиента),
• Некорректное применение (использование для разграничения доступа программы, в которой нет
аутентификации),
• Некорректные настройки (отсутствие запрета модификации настроек безопасности для пользователя),
• и т.д.
8. Тестирование
• С виду наиболее простой подход.
• Позволяет контролировать качество вариантов использования, пришедших в голову тестировщику.
• Наиболее проработанный и везде применяемых подход (функциональное тестирование, нагрузочное
тестирование, регрессионное тестирование, Unit Test).
• Сложность проведения качественного тестирования
10. Типизированные языки программирования
и контроль времени компиляции
• Позволяет выявлять наиболее простые «опечатки» программиста.
• Метод быстрой разработки: недостатки.
11. Встраивание проверок и ограничений в код,
использование "безопасных" функций и языков
высокого уровня
• Встраивание проверок и ограничений позволяет выявлять проблемы во время исполнения и
реагировать на них (контроль переполнения буфера в Visual С++).
• Использование «безопасных» функций позволяет избежать типичных ошибок программирования
• char * strcpy ( char * destination, const char * source );
• char * strncpy ( char * destination, const char * source, size_t num );
№3 в Top 25 CWE: «Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')»
• Языки высокого уровня позволяют детальнее продумывать архитектуру, не заботясь о деталях
реализации.
12. Доказательство правильности свойств
программ
• Минус: возможность работы только с небольшими программами
• Требуется высокая компетенция экспертов
• Формальное доказательство
• Model Checking
• Pi-calculus
13. Статический анализ
• Выявление «нехитрых» ошибок
• Значительное количество ложных срабатываний
15. Статический анализ кода
• Анализ, проводимый путём исследования исходных текстов или исполняемых файлов БЕЗ запуска кода.
• Автоматическое выявление возможных уязвимостей кода БЕЗ исполнения кода.
• Статический анализ показывает на возможный недочёт.
• do {} while true;
• char *p, *k;
• p=k;
• *k=10;
• If ( p ) {};
16. Лексический контроль заданных правил
• Фактически – применение регулярных выражений.
• k = j/0;
• i = 0;
• …
• k = j/i;
• Сообщения компиляторов
• Большинство (простейшие) утилиты поиска недостатков кода
• Утилиты проверки правил оформления кода
17. Анализ программы без учета потока
управления
• Прямой обход результатов лексического, синтаксического или семантического разбора.
• i = 0;
• …
• k = j/i;
• Не используемые переменные, «устаревшие» функции,
• Сообщения умных компиляторов
• Lint
• CppCheck
18. Анализ программ с учётом потока
управления
• Прямой обход результатов лексического, синтаксического или семантического разбора.
• i = 0;
• …
• k = j/i;
• Использование переменной до присвоения ей значения, недостижимый код
• Klockwork, Coverity, VivaCore
• Pvs-studio
19. Анализ аннотированного кода
• Аннотирование кода позволяет упростить работу алгоритма
• int readData( __out_bcount_part( maxLength, *length ) void *buffer, const int maxLength, int *length );
• Visual Studio (PreFast)
20. Примеры результатов PVS-studio
• There are identical sub-expressions 'height <= 0' to the left and to the right of the '||' operator.
• if (width <= 0 || height <= 0 || !data
• || INT_MAX/sizeof(uchar *) < uint(height)
• || INT_MAX/uint(depth) < uint(width)
• || bpl <= 0
• || height <= 0
• || bpl < min_bytes_per_line
• || INT_MAX/uint(bpl) < uint(height))
• return d;
• This is a nonsensical comparison: pointer >= 0.
• MessageItem *ContextItem::findMessage(const QString &sourcetext, const QString &comment) const
• if (c->findMessage(m->text(), m->comment()) >= 0)
21. Примеры результатов PVS-studio
• The 'throw' operator inside the destructor should be placed within the try..catch block. Raising exception inside
the destructor is illegal.
• # define QT_RETHROW throw
• QObject::~QObject()
• {
• if (d->isSignalConnected(0)) {
• QT_TRY {
• emit destroyed(this);
• } QT_CATCH(...) {
• // all the signal/slots connections are still in place - if we don't
• // quit now, we will crash pretty soon.
• qWarning("Detected an unexpected exception in ~QObject while emitting destroyed().");
• QT_RETHROW;
• }
• }
• }
22. Примеры результатов PVS-studio
• Pointer to local variable 'tmp' is stored outside the scope of this variable. Such a pointer will become invalid.
•
• QList<QGraphicsItem *> QGraphicsSceneBspTree::items(const QRectF &rect, bool onlyTopLevelItems) const
• {
• QList<QGraphicsItem *> tmp;
• findVisitor->foundItems = &tmp;
• findVisitor->onlyTopLevelItems = onlyTopLevelItems;
• climbTree(findVisitor, rect);
• // Reset discovery bits.
• for (int i = 0; i < tmp.size(); ++i)
• tmp.at(i)->d_ptr->itemDiscovered = 0;
• return tmp;
• }
23. Примеры результатов PVS-studio
• Pointer to local variable 'tmp' is stored outside the scope of this variable. Such a pointer will become invalid.
•
• QList<QGraphicsItem *> QGraphicsSceneBspTree::items(const QRectF &rect, bool onlyTopLevelItems) const
• {
• QList<QGraphicsItem *> tmp;
• findVisitor->foundItems = &tmp;
• findVisitor->onlyTopLevelItems = onlyTopLevelItems;
• climbTree(findVisitor, rect);
• // Reset discovery bits.
• for (int i = 0; i < tmp.size(); ++i)
• tmp.at(i)->d_ptr->itemDiscovered = 0;
• return tmp;
• }
24. Примеры результатов CppCheck
• (error) Uninitialized variable: cc
int wfp_dispatch(wfp *p, int cnt, wfp_handler callback, u_char *user)
{
int cc;
if (p->cc == 0)
{
cc = p->packet->ulBytesReceived;
}
else
bp = p->bp;
#define bhp ((wfp_hdr *)bp)
ep = bp + cc;
}
25. Примеры результатов CppCheck
• (error) Uninitialized variable: cc
int wfp_dispatch(wfp *p, int cnt, wfp_handler callback, u_char *user)
{
int cc;
if (p->cc == 0)
{
cc = p->packet->ulBytesReceived;
}
else
bp = p->bp;
#define bhp ((wfp_hdr *)bp)
ep = bp + cc;
}