Проблематика: Объёмы кода растут; Плотность ошибок растёт нелинейно; Все хотят качественный и БЕЗОПАСНЫЙ код; Старых методов контроля качества уже недостаточно.
4. 4/52
Проблематика
• Объёмы кода растут
• Плотность ошибок растёт
нелинейно
• Все хотят качественный и
БЕЗОПАСНЫЙ код
• Старых методов контроля
качества уже недостаточно
5. 5/52
• Ядро Linux 1.0.0 : 176 250 строк кода
• Ядро Linux 4.11.7: 18 373 471 строк кода
• Photoshop 1.0 : 128 000 строк кода
• Photoshop CS 6 : 10 000 000 строк кода
Рост объёма кода некоторых проектов
6. 6/52
Плотность ошибок (на 1 KLOC)
0
20
40
60
80
100
< 2 2-16 16-64 64-512 > 512
"Estimating Software Costs: Bringing Realism to Estimating" (Capers Jones, 2007)
10. 10/52
Аттракцион “Найди ошибку” (проект Mono)
V3012 The '?:' operator, regardless of its conditional expression, always
returns one and the same value: Color.FromArgb (150, 179, 225).
ProfessionalColorTable.cs 258
14. 14/52
• Не заменяет, но дополняет обзоры кода
• Позволяет контролировать качество кода в больших
проектах
• Раннее обнаружение проблем
• Максимальное покрытие кода
• Поиск разнообразных паттернов ошибок
Статический анализ кода
16. 16/52
• Сложно искать даже простейшие перестановки:
(A + B == B + A)
• Макросы: кто их раскроет?
• Типы: кто вычислит цепочку typedef?
• Значения: как узнать, что индекс вышел за границу массива?
Регулярные выражения не работают!
17. 17/52
А что работает?
• Сопоставление с шаблоном (pattern-based analysis)
• Вывод типов (type inference)
• Символьное выполнение (symbolic execution)
• Анализ потока данных (data-flow analysis)
• Аннотирование методов (method annotations)
18. 18/52
Сопоставление с шаблоном (pattern-based analysis)
Linux Kernel
static ssize_t lp8788_show_eoc_time(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lp8788_charger *pchg = dev_get_drvdata(dev);
char *stime[] = { "400ms", "5min", "10min", "15min",
"20min", "25min", "30min" "No timeout" };
....
}
V653 A suspicious string consisting of two parts is used for array initialization.
It is possible that a comma is missing. Consider inspecting this literal: "30min"
"No timeout". lp8788-charger.c 657
19. 19/52
Вывод типов (type inference)
template<class T, size_t N> struct X
{
T A[N];
void Foo()
{
memset(A, 0, sizeof(T) * 10);
}
};
void Do()
{
X<int, 5> a;
a.Foo();
}
V512 Instantiate X < int, 5 >: A call of the 'memset' function will lead to overflow of
the buffer 'A'. test.cpp 127
20. 20/52
Символьное выполнение (symbolic execution)
void F(int X)
{
int A = X;
int B = X + 10;
int Q[5];
Q[B - A] = 1;
}
V557 Array overrun is possible. The 'B - A' index is pointing beyond array
bound. test.cpp 126
26. 26/52
SAST - Static Application Security Testing
• Статический анализ, нацеленный на поиск и предотвращение
уязвимостей
• Уязвимости - те же самые обыкновенные ошибки (по данным
NIST, более 60%)
• Инструменты SAST помогают предотвращать уязвимости и
обеспечивают поддержку стандартов безопасной разработки:
CWE, MISRA, SEI CERT и т.п.
28. 28/52
Поиск уязвимостей
Для старого кода оптимален поиск известных уязвимостей:
• Аналогия - антивирусы
• Нет ложных срабатываний
• Но находится только то, что уже известно
• Особенно полезно в больших старых проектах
Для нового кода более эффективен метод поиска дефектов
кода с целью предотвращения уязвимостей.
31. 31/52
Путь к реальной уязвимости
CWE - Common Weakness
Enumeration
CVE - Common Vulnerabilities
and Exposures
32. 32/52
CWE
• CWE™ is a community-developed list of common
software security weaknesses
• https://cwe.mitre.org
• Cписок из более чем 800 потенциальных
уязвимостей, которые могут стать реальными
33. 33/52
CWE: примеры потенциальных уязвимостей
• CWE-14: Compiler Removal of Code to Clear Buffers
• CWE-20: Improper Input Validation
• CWE-91: XML Injection
• CWE-457: Use of Uninitialized Variable
• CWE-467: Use of sizeof() on a Pointer Type
• CWE-562: Return of Stack Variable Address
34. 34/52
CWE-14 (Compiler Removal of Code to Clear Buffers)
void win32_dealloc(struct event_base *_base, void *arg) {
struct win32op *win32op = arg;
....
memset(win32op, 0, sizeof(win32op));
free(win32op);
}
V597 The compiler could delete the 'memset' function call, which is used to flush
'win32op' object.
35. 35/52
CWE-687 (Function Call With Incorrectly Specified Argument Value)
void win32_dealloc(struct event_base *_base, void *arg) {
struct win32op *win32op = arg;
....
memset(win32op, 0, sizeof(win32op));
free(win32op);
}
V579 The memset function receives the pointer and its size as arguments. It is
possibly a mistake. Inspect the third argument.
36. 36/52
CWE-563 (Assignment to Variable without Use)
public string Region
{
get {....}
set
{
if (String.IsNullOrEmpty(value))
{
this.linker.s3.region = "us-east-1";
}
this.linker.s3.region = value;
}
}
V3008 The 'this.linker.s3.region' variable is assigned values twice successively.
Perhaps this is a mistake.
37. 37/52
CWE-674 (Uncontrolled Recursion)
OnFailure? onFailure = null;
public OnFailure? OnFailure
{
get { return this.OnFailure; }
set { this.onFailure = value; }
}
V3110 Possible infinite recursion inside 'OnFailure' property.
38. 38/52
CVE
• CVE® is a list of publicly known cybersecurity
vulnerabilities
• https://cve.mitre.org/
• Список из более чем 114 000 реальных уязвимостей,
найденных в приложениях
39. 39/52
CVE-2012-2122
typedef char my_bool;
my_bool
check_scramble(const char *scramble_arg, const char *message,
const uint8 *hash_stage2)
{
....
return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
}
V642 [CWE-197] Saving the 'memcmp' function result inside the 'char' type variable
is inappropriate. The significant bits could be lost breaking the program's logic.
40. 40/52
CVE-2013-4258
if (NasConfig.DoDaemon) {
openlog("nas", LOG_PID, LOG_DAEMON);
syslog(LOG_DEBUG, buf);
closelog();
} else {
errfd = stderr;
}
Network Audio System
V618 [CWE-134] It's dangerous to call the 'syslog' function in such a manner, as
the line being passed could contain format specification. The example of the safe
code: printf("%s", str).
41. 41/52
CVE-2014-1266
static OSStatus
SSLVerifySignedServerKeyExchange(....)
{
....
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
....
fail:
....
}
V640 [CWE-483] The code's operational logic does not correspond with its formatting.
V779 [CWE-561] Unreachable code detected. It is possible that an error is present.
43. 43/52
MISRA C/C++
• Motor Industry Software Reliability Association
• Стандарт кодирования, который уменьшает вероятность
допущения ошибки для ответственных встраиваемых
систем
• Проприетарный
• MISRA C 2012 cодержит 143 правила
• MISRA C++ 2008 cодержит 228 правил
44. 44/52
MISRA C/C++ (некоторые правила)
• Не используйте восьмеричные константы
• Не используйте goto
• Функция должна иметь ровно одну точку выхода
• Не используйте функции стандартной библиотеки
(atof/…/abort/exit/getenv/system/…)
• Не используйте динамические аллокации
• Не используйте объединения
• Каждый case должен заканчиваться break или throw
45. 45/52
SEI CERT
• Стандарт кодирования
• Разрабатывается координационным центром CERT
(CERT Coordination Center, CERT/CC)
• Предназначен для языков C, C++, Java, Perl
• Весьма похож на CWE
46. 46/52
SEI CERT (некоторые правила)
• MSC06-C: Beware of compiler optimizations
• INT33-C: Ensure that division and remainder operations
do not result in divide-by-zero errors
• EXP33-C, EXP53-CPP: Do not read uninitialized memory
• ARR01-C: Do not apply the sizeof operator to a pointer
when taking the size of an array
• DCL30-C: Declare objects with appropriate storage
durations
48. 48/52
Внедряем и используем SAST правильно
• Выбираем подходящий анализатор
• Настраиваем
• Проверяем проект, рассматриваем текущие
предупреждения как “технический долг”
• Работаем с новыми предупреждениями
• Внедряем SAST в системы CI
• Внедряем SAST на рабочих местах
• ….
• PROFIT!!!
50. 50/52
Снижаем потери
• Возникновение уязвимости
• Обнаружение с помощью SAST, исправление
• Прямые и косвенные потери:
• Эксплуатация злоумышленниками
• Bug bounty
• Репутация
• Исправление
• Выпуск обновления
$
$
$
$
$
$
$
51. 51/52
Выводы
Проблемы с безопасностью дорого обходятся, если
попадают в конечный продукт
Инструменты SAST – один из способов поиска уязвимостей
Тем не менее, используйте все другие доступные вам
методы
Если компания зарабатывает деньги, используя
программный код, она просто обязана думать о его
безопасности