Statyczna analiza kodu
Analiza statyczna kodu - analiza struktury kodu źródłowego lub kodu skompilowanego bez jego uruchomienia.
Static Analysis Software Testing (SAST) - narzędzia do automatycznej analizy statycznej
Analiza statyczna a inspekcja kodu („code review”)
SDL for Agile
Agile Development Using Microsoft Security Development Lifecycle - analiza statyczna w każdym sprincie
Źródło: http://www.microsoft.com/security/sdl/discover/sdlagile.aspx
Metody analizy
analiza leksykograficzna - wyszukiwanie niebezpiecznych konstrukcji w kodzie źródłowym, zazwyczaj na podstawie zestawu reguł, różnych heurystyk i dopasowania do wzorców błedów
metody formalne - oparte na matematycznej definicji zachowania programu
metryki kodu źródłowego - ocena jakości kodu źródłowego na podstawie danych statystycznych.
Zalety
Szybkość działania - szybkie wykrywanie błędów, których naprawa jest prosta i mało kosztowna
Łatwość użycia - proste we wdrożeniu w cykl wytwarzania oprogramowania
Automatyzacja - integracja z narzędziami continius integrations
Możliwości rozszerzania: własne reguły, wtyczki, …
Integracja z innymi narzędziami: serwery automatyzacji, IDE, kontrola wersji
Dużo darmowych narzędzi
Wady
Wymagany dostęp do źródeł
Reguły wykrywają zazwyczaj proste błędy i nie są w stanie wyeliminować ręcznego sprawdzenia kodu
Dużo szumu, zbyt czułe - duże prawdopodobieństwo zaklasyfikowanie poprawnego fragmentu jako błędu (false positive)
Każde narzędzie zazwyczaj pokrywa pewien zakres testów (do 14% błędów?!). Dlatego warto korzystać z kilku różnych skanerów kodu. Istnieją narzędzia integrujące wiele narzędzi SAST, np:
CodeEx, Yast (open source)
Czego dotyczy analiza statyczna
analiza poprawności składni
luki w bezpieczeństwie, także błędy które mogą pojawić się przy specyficznych danych wejściowych
detekcja backdoors, niebezpieczne i nieaktualne funkcje, wycieki pamięci, przepełnienie bufora, używanie niezainicjowanych zmiennych, SQL Injections,
jakość kodu, ocena stylu, powtórzenia kodu, nieużywane fragmenty kodu, …
wydajność, wykrywanie wąskich gardeł, niewydajne konstrukcje, sugestie dotyczące poprawienia wydajności
zgodność z dobrymi praktykami, zachowanie standardów, norm nazewniczych, problemy z przenośnością kodu
Dlaczego analizować kod?
Statyczna analiza programu pozwala na:
zwiększenie wydajności i stabilności poprzez zasady oparte na dobrych praktykach,
unikniecie typowych błędów podczas programowania,
dostarczenie struktury do zarządzania standardami kodu.
wymuszenie zasad i standardów pisania kodu
zwiększanie bezpieczeństwa poprzez kolejny etap testowania
analizując sygnalizowane błędy można się sporo nauczyć na temat dobrych praktyk bezpiecznego programowania
Dlaczego analizować kod?
Koszt naprawy błędu w zależności od momentu wykrycia
Źródło: http://www.microsoft.com/security/sdl/about/benefits.aspx
Narzędzia
Lint - UNIX V7 1979, historyczny program od którego nazwy często określa się narzędzia do analizy i szukania błedów
Wielojęzykowe
rats (rough auditing tool for security) C, C++, Perl, PHP, Python
PMD Java, JavaScript, XML, XSL (zawiera CPD analiza powtórzeń: C, C++, C#, PHP, Ruby, Fortran)
Yasca Java, C/C++,
HTML, JavaScript, ASP, ColdFusion, PHP, COBOL, .NET, and other languages + integracja z innymi SAT
-
Wiele innych:
Kompilatory
Kompilatory oprócz sprawdzania składni również potrafią sygnalizować możliwość występowania błędu w kodzie.
GCC warning options
-pedantic
tylko czyste ISO C i ISO C++
-Wall
wszystkie ostrzeżenia
-Werror
ostrzeżenia generują błąd kompilacji
-Wextra
dodatkowe ostrzeżenia wykraczające poza Wall
Visual C++: warning level 4
cppcheck
Cppcheck
Online Demo
Wykrywane błedu
wykroczenia poza zakres tablicy
wycieki pamięci
odwołania do adresu NULL
niezainicjowane zmienne
używanie przestarzałych lub niebezpiecznych funkcji
wykrywanie niedostępnych fragmentów kodu oraz powtórzeń kodu
wiele innych …
-
Ograniczenia
Jest wiele typów błędów, które ciężko jest wykryć, np błędy związane są z konfiguracją lub logiką biznesową
Problemem są zależności, dodatkowe moduły, biblioteki, konteksty dodawane przez frameworki
Skomplikowane algorytmy i architektury bardzo ciężko jest analizować
// calculate the number of days
int days = hours / 23;
Przykład
int main()
{
char *x;
int a[20];
*x = 5;
a[20] = 5;
return 0;
}
cppcheck --enable=all test1.c
Checking test1.c...
[test1.c:4]: (style) Variable 'x' is not assigned a value.
[test1.c:8]: (style) Variable 'a' is assigned a value that is never used.
[test1.c:8]: (error) Array 'a[20]' accessed at index 20, which is out of bounds.
[test1.c:7]: (error) Uninitialized variable: x
Checking usage of global functions..
Przykład
#include <stdio.h>
int main()
{
char c;
while (c != 'x');
{
c = getchar();
if (c = 'x') return 0;
switch (c) {
case '\n':
case '\r':
printf("Newline\n");
default:
printf("%c",c);
}
}
return 0;
}
Źródło: wikipedia.org
Przykład: buffer overflow
Śledzenie wywołań funkcji:
void f1(char *s)
{
s[20] = 0;
}
void f2()
{
char a[10];
if (x + y == 2) {
f1(a);
}
}
Array 'a[10]' index 20 out of bounds
Prawie to samo ale cppcheck
już nie wykrywa błędu
void f3(char *s)
{
if (x + y == 2) {
s[20] = 0;
}
}
void f4()
{
char a[10];
f3(a);
}
Wycieki pamięci
void f()
{
char *a = malloc(10);
if (x + y == 2) {
return;
}
free(a);
}
Wynik cppcheck
[mem.c:5]: (error) Memory leak: a
void f2(int x)
{
char *a = 0;
if (x == 10)
a = malloc(10);
if (x == 20)
free(a);
}
Brak błedu?!
Automatyzacja testów
kiedy analizować: przed/po commicie, po każdym buildzie, po zapisaniu pliku
IDE i ich edytory sprawdzają składnię też (rozszerzenia Resharper)
testy po stronie developera lub po stronie repozytorium (serwera autoamtyzacji)
skrypty uruchamiane po zatwierdzeniu zmiany + powiadomienia (email, inne alerty), w SVN hooks/post-commit
uniemożliwienie zatwierdzenia kodu z błędami, w SVN hooks/pre-commit
serwery automatyzacji, np.
Hudson
Przykłady: FindBugs, Cppcheck+TortoiseSVN SVN pre-commit
Źródła