56
OBRONA
HAKIN9 4/2008
P
rzy tworzeniu bezpiecznych programów
naley zwróci szczególn uwag na kilka
istotnych czynników wpywajcych na
ogólne bezpieczestwo rozwizania. Cay tekst
bazuje na przykadzie systemu Windows i
aplikacji pisanych na platformie .NET.
Problem bezpieczeństwa aplikacji jest bardzo
szeroko omawianym tematem w różnego
rodzaju opracowaniach. Niemniej jednak
warto kompleksowo przyjrzeć się tej kwestii.
Ogólnie przyjętym stwierdzeniem jest potrzeba
znalezienia złotego środka przy tworzeniu
poszczególnych rozwiązań. Należy bardzo
mocno wyważyć bezpieczeństwo z łatwością
użycia aplikacji przez użytkowników końcowych.
Każda aplikacja może być bardzo bezpieczna
i uwzględniać wszystkie możliwe aspekty
bezpieczeństwa, ale z drugiej strony będzie
wtedy na pewno niewygodna w obsłudze. Jeśli
przekształcimy to stwierdzenie, będziemy mogli
powiedzieć, że programy łatwe w użyciu są
aplikacjami niebezpiecznymi. No właśnie, ale
czy aby na pewno tak jest?
Bezpieczeństwo aplikacji
Bezpieczeństwo to kilka różnego rodzaju
warstw, a co za tym idzie – różne elementy
chroniące nasz system. Jeśli przyjrzymy się
Rysunkowi 1, zobaczymy, w jaki sposób można
umiejscowić takie warstwy.
Dane i aplikacja to oczywiście kluczowe
elementy układanki. Oczywiście oba z tych
ARTUR ŻARSKI
Z ARTYKUŁU
DOWIESZ SIĘ
o podstawowych zagadnieniach,
które mogą podnieść
bezpieczeństwo tworzenia
i wdrażania aplikacji.
CO POWINIENEŚ
WIEDZIEĆ
znać podstawową znajomość
C/C++,
pojęcia związane
z bezpieczeństwem danych.
elementów posiadają własne zabezpieczenia.
I tak, dane mogą być szyfrowane przy pomocy
EFS (Encrypted File System) oraz BitLocker’a.
Do zabezpieczeń może być użyty IRM oraz
RMS, a całość dodatkowo chroniona będzie
przy pomocy ACL w NTFS. Aplikacja natomiast
posiada własne zabezpieczenia dostępu,
dobrze zdefiniowaną architekturę, kod oraz
różnego rodzaju procedury walidacji.
Idąc dalej – nasz serwer (host) posiada
zabezpieczenia systemu operacyjnego. Ma
hasła dostępu do tegoż systemu operacyjnego.
Dodatkowo jest często aktualizowany
– wgrywane są zawsze najnowsze poprawki
bezpieczeństwa. Użytkownicy mają możliwość
użycia SmartCard z zainstalowanymi
certyfikatami.
Kolejny istotny element to cała infrastruktura
sieciowa. Może być zabezpieczona przy
pomocy IPSec czy IDS. Krańce sieci
Stopień trudności
Bezpieczne a
niebezpieczne
aplikacje
Aplikacje i ich bezpieczeństwo to nie tylko i wyłącznie proces
ich tworzenia, to również modelowanie zagrożeń, projektowanie
rozwiązania oraz architektura. Wszystkie te czynniki składają się
na stworzenie bezpiecznej lub niebezpiecznej aplikacji.
Listing 1.
Przykład przepełnienia bufora
int
ryzykowna1
(
char
*
pLancuch
)
{
int
nLicznik
=
0
;
char
pBufor
[
_MAX_PATH
]
;
strcpy
(
pBufor
,
pLancuch
);
for
(;
pBufor
;
pBufor
++)
if
(*
pBufor
==
'\\'
)
nLicznik
++;
return
nLicznik
;
}
57
BEZPIECZNE A NIEBEZPIECZNE APLIKACJE
HAKIN9
4/2008
korporacyjnej (na rysunku granica sieci)
zabezpieczone są przy pomocy firewall’a,
a użytkownicy łączący się przy pomocy
VPN, zanim uzyskają dostęp do sieci,
przechodzą kwarantannę sprawdzającą
'poprawność' komputera. Mając serwer
oraz infrastrukturę pozostaje nam
zapewnienie fizycznego bezpieczeństwa
– czyli serwerownia ze strażnikami,
dobrze zamkniętymi drzwiami,
monitoringiem etc.
Ostatnim, ale jednym z
najważniejszych, elementem jest
świadomość użytkowników (prawników
firmy). Należy te osoby edukować, mówić
im, czym jest bezpieczeństwo, 'przestawiać'
na bezpieczne myślenie (np. stanowczo
eliminować żółte karteczki z zapisanym
hasłem, przyklejane pod biurkiem).
Wszystkie te elementy mogą
wydawać się oczywiste, niemniej jednak
bardzo często zdarza się, że krytyczne
aplikacje uruchamiane są 'tymczasowo'
pod biurkiem administratorów lub
programistów. Do tego wszystkiego
dochodzi jeszcze problem analogowo-
cyfrowy, w przypadku którego jedynym
punktem jest ostatni z wymienionych
wcześniej – a więc świadomość
zagrożeń (Rysunek 2 – źródło Internet).
Modelowanie zagrożeń
Modelowanie zagrożeń to rodzaj
analizy bezpieczeństwa, którego
celem jest zwiększenie sumarycznego
bezpieczeństwa aplikacji. Należy przy
tym pamiętać, że zagrożenie nie oznacza
słabego punktu. Na sumaryczne
bezpieczeństwo aplikacji składa się kilka
czynników: znalezienie luk infrastruktury,
ocena zagrożeń bezpieczeństwa czy
określenie środków zaradczych. Na
czym polegają poszczególne czynniki?
Jest to przykładowo analiza wszystkich
możliwych wejść do systemu, w
szczególności miejsc, w których z
zewnątrz dostarczane są dane – np.
API, gniazda, Web Service, pliki czy
dane wprowadzane bezpośrednio
przez użytkownika systemu. Następnie
sprawdzanie zasobów, czyli wszystko, co
może być potencjalnym źródłem ataku –
na przykład dane, pliki konfiguracyjne etc.
Modelowaniu podlega również poziom
uprzywilejowania, czyli role użytkownika
potrzebne do wejścia do systemu czy
uzyskania praw dostępu do zasobów, a
także sposób autoryzacji.
Istnieje kilka metod modelowania
zagrożeń, wśród nich technika STRIDE
(Spoofing, Tampering, Repudiation,
Information disclosure, Denial of service,
Elevation of privilege). Poszczególne
odpowiedniki rodzajów zagrożeń wraz z
przykładami przedstawia Tabela 1.
Do tego mamy jeszcze ocenę
zagrożeń DREAD (Damage Potential,
Reproducibility, Exploitability, Affected
Users, Discoverability), czyli kolejno:
• D – Możliwość zniszczeń,
• R – Powtarzalność,
• E – Możliwość wykorzystania,
• A – Użytkownicy, których dotyczy
problem,
• D – Możliwość wykrycia.
Rysunek 1.
Warstwy bezpieczeństwa
systemów
����
���������
��������������������
����
�������������
�����������������������
������������������������
�����������������
Tabela 1.
Techniki określania zagrożeń STRIDE
Fałszowanie
Fałszowanie wiadomości e-mail
Powtarzanie uwierzytelniania
Zniekształcanie
Zmiana danych podczas transmisji
Zmiana danych w bazie danych
Zaprzeczanie
Usunięcie istotnych danych i zaprzeczanie temu
Zakup produktu i zaprzeczanie temu
Ujawnianie informacji
Ujawnianie informacji w komunikatach o błędach
Ujawnianie kodu w witrynie sieci Web
Odmowa usługi
Zalewanie usługi sieci Web nieprawidłowymi żądaniami
Zalewanie sieci pakietami SYN
Podwyższanie uprawnień
Uzyskiwanie uprawnień administratora
Używanie zestawu w pamięci GAC do tworzenia konta
Tabela 2.
Analiza potencjalnych zagrożeń
Zagrożenie
D R
E
A
D Razem
Ocena
Napastnik uzyskuje poświadczenia
3
3
2
2
2
12
Wysoka
Wstrzyknięcie poleceń SQL
3
3
3
3
2
14
Wysoka
Tabela 3.
Przydatne przełączniki oraz dodatkowe biblioteki
Przełącznik/Biblioteka
Uwagi
/GS: Przepełnienie stosu
Skuteczność 100%
/GS: Przekierowanie wskaźnika, zmiana
wartości EBP
Skuteczność niska (chyba że trafi na adres
zwrotny)
RTC: stos niezerowy
Pomoc przy śledzeniu
PREfast: analizator kodu
Pożyteczny; dodatkowe ostrzeżenia
SAL:dodatkowe adnotacje (_deref, _ecount
…)
Duża skuteczność; wykrycie „losowych”
błędów; pomoc w analizie
Application Verifier
Dobry pomocnik testera
ACGP: rozrzucenie kodu w segmencie
Duża skuteczność; wykrycie „losowych”
błędów
OBRONA
58
HAKIN9 4/2008
BEZPIECZNE A NIEBEZPIECZNE APLIKACJE
59
HAKIN9
4/2008
Do każdej z kategorii należy przypisać
odpowiednią wagę zagrożenia – np.
Wysokie (3), Średnie (2) oraz Niskie
(1). Analizując potencjalne zagrożenia
możemy określić jego ocenę. Przykład
znajduje się w Tabeli 2.
Proces modelowania zagrożeń został
opisany przez Microsoft już jakiś czas
temu i przedstawia się następująco:
• Zidentyfikować zasoby – czyli
określenie typów danych, które mogą
być interesujące dla napastników.
• Stworzyć przegląd architektury –
analiza komponentów pod względem
wejść aplikacji.
• Dekompozycja aplikacji – analiza
funkcji aplikacji (każdej z osobna) i
określenie ścieżek przepływu danych.
• Identyfikacja zagrożeń – określenie
potencjalnych błędów w aplikacji
oraz potencjalnych miejsc ataku.
• Dokumentacja zagrożeń – spisanie
wszystkich zagrożeń.
• Ocena poziomu zagrożenia
– określenie możliwości wykrycia
i wystąpienia poszczególnych
zagrożeń.
Wewnątrz firmy Microsoft stosowana
jest metodologia Security Development
Lifecycle. Wykorzystywana ona była
między innymi przy tworzeniu SQL
Server 2005, systemów Windows Vista
oraz Windows Server 2008. Zgodnie z
tą metodyką należy zwrócić uwagę na
pewne zasady:
• Okresowe OBOWIĄZKOWE szkolenia
z zakresu bezpieczeństwa dla
WSZYSTKICH zaangażowanych w
proces tworzenia aplikacji.
• Doradca bezpieczeństwa dla
KAŻDEGO komponentu.
• Modelowanie zagrożeń jako część
procesu projektowego.
• Przeglądy bezpieczeństwa i
testowanie przewidziane w
harmonogramie projektu.
• Zdefiniowanie i stosowanie metryk
bezpieczeństwa dla zespołów
projektowych.
Trochę praktyki
Oprócz ogólnych elementów
bezpieczeństwa systemu
informatycznego, baczną uwagę należy
również zwrócić na sposób pisania
kodu naszej aplikacji. Warto zwrócić
uwagę na:
• Bezpieczeństwo w projektowaniu
i implementacji – jest to proces
kładący nacisk na bezpieczeństwo
oprogramowania, który również
podlega modelowaniu zagrożeń.
Szczególną uwagę należy
zwrócić na audyt kodu oraz testy
bezpieczeństwa.
• Bezpieczne wartości domyślne
– dzięki którym minimalizujemy
możliwy obszar sposobów ataku
(attack surface).
• Bezpieczna instalacja – warto
również zwrócić uwagę na ten
Rysunek 3.
Dekompozycja aplikacji
������
�����������
����
���������
�
�������
�����������
�����������
���������
�����
��
���������
�����������
������������
�������
����
������������
�������������
�����������
�����
Rysunek 2.
Problem analogowo-cyfrowy
OBRONA
58
HAKIN9 4/2008
BEZPIECZNE A NIEBEZPIECZNE APLIKACJE
59
HAKIN9
4/2008
aspekt, aby wykorzystać mechanizmy
systemu operacyjnego i .NET
Framework (np. CAS – Code Access
Security).
Przykładów niebezpiecznego kodu
jest wiele – najbardziej popularnym
z nich jest przepełnienie bufora.
Jest to zazwyczaj główna przyczyna
problemów, spotykana najczęściej w
przypadku kodu natywnego (C/C++)
oraz API systemu operacyjnego.
Ogólnie rzecz ujmując, polega na
nadpisaniu „za dużym” parametrem
stosu lub sterty, przepełnienia licznika
czy też przekroczenia zakresu tablicy.
Stosowanie pewnej grupy dobrze
opisanych funkcji (do których można
zaliczyć strcpy, gets, scanf, sprintf, strcat
i inne) zwiększa ryzyko powstawania
przepełnień bufora, dlatego ich
stosowanie jest gorąco odradzane.
Przykład błędu przedstawiony jest na
Listingu 1.
Na Listingu 1 w kodzie od razu
widać słaby punkt — parametr pBufor
może zostać przepełniony, jeśli bufor
wskazywany przez pLancuch jest dłuższy
niż
_ MAX _ PATH
.
Można oczywiście wykryć część
tego typu problemów, wykorzystując
odpowiednie przełączniki kompilatora i
biblioteki przedstawione w Tabeli 3.
W przypadku kodu zarządzanego
mamy pewnego rodzaju automat
zabezpieczający przed przepełnieniem
bufora, wyjściem poza zakres tablicy
czy też nieprawidłowym kodem
wykonywalnym.
Gotowce
pomagające w pracy
Rozwiązaniem potencjalnych problemów
może być Enterprise Library stworzone
przez Microsoft przez grupę Patterns &
Practices (http://msdn2.microsoft.com/
en-us/library/aa480453.aspx).
Enterprise Library to zestaw różnego
rodzaju bloków aplikacji (funkcjonalnych).
Bloki te są opisanymi gotowymi
rozwiązaniami oraz kawałkami kodu,
który należy tylko wstawić do własnej
aplikacji wg zaleceń bez konieczności
tworzenia własnych takich rozwiązań.
Wśród gotowych bloków możemy
znaleźć między innymi: Caching,
Cryptography, Data Access, Exception
Handling, Logging, Security, Validation,
Policy Injection. W naszym przypadku
istotne będą dwa bloki: Cryptography
Application Block oraz Validation
Application Block. Należy pamiętać,
że nie jest to rozwiązanie wszystkich
problemów, ale warto się mu przyjrzeć,
ponieważ jest po prostu pożyteczne dla
programistów.
Podsumowanie
Jak widać (i jak wiadomo), problem
bezpiecznych bądź niebezpiecznych
aplikacji jest nader złożony. Wyróżnić
można bardzo wiele aspektów tworzenia
bezpiecznych aplikacji, na które należy
zwrócić uwagę. Przede wszystkim są to:
dobrze zdefiniowany proces tworzenia
aplikacji, edukacja zespołu programistów,
zachowanie jakości kodu oraz stworzenie
bezpiecznej architektury.
Jednym z najistotniejszych punktów
tworzenia rozwiązania jest również
kodowanie. Dla przykładu bardzo
wiele funkcji z biblioteki języka C jest
potencjalnie niebezpiecznych np.:
gets
,
strcpy
,
strcat
,
sprintf(“%s”)
Warto zwrócić uwagę na środki
wspomagające tworzenie bezpiecznego
kodu, czyli przede wszystkim pozwalające
na automatyczny code review, statyczną
analizę kodu – np.
FxCop
. No i oczywiście
testy. Testy, testy i jeszcze raz testy na
występowanie różnych luk zabezpieczeń.
Artur Żarski
Jest pracownikiem firmy Microsoft. Na co dzień
zajmuje się m.in. tworzeniem rozwiązań w oparciu
o SQL Server w różnych aspektach – bazy
relacyjne, usługi integracyjne, usługi analityczne.
Jest certyfikowanym administratorem baz danych
(MCDBA).
Kontakt z autorem: arturz@microsoft.com
R
E
K
L
A
M
A