Istotnym elementem nauki są także komentarze. Na wczesnym etapie mają one pomagać w zrozumieniu, co dokładnie robi dana linia lub funkcja. Komentarze pełnią funkcję tłumacza pomiędzy zamysłem programisty a faktyczną implementacją, co jest szczególnie ważne, gdy ktoś dopiero uczy się składni języka i podstawowych konstrukcji. Dzięki temu łatwiej wychwycić błędy logiczne i lepiej zrozumieć własny tok myślenia.
Z czasem, wraz ze wzrostem doświadczenia, podejście do komentarzy i stylu pisania kodu zwykle ewoluuje. Jednak fundamenty wyniesione z początkowej nauki – dbałość o czytelność, jasną strukturę i przewidywalność – pozostają kluczowe. Tymczasem to czasami poważny błąd. W kwestii cyberbezpieczeństwa zły kod to czasami dobry kod.
Nieczytelność staje się zaletą
To podejście zaczyna coraz częściej obowiązywać w świecie bezpieczeństwa. Dla specjalistów od kryptografii czy ochrony systemów celowe zawiłe pisanie kodu nie jest wadą, lecz pożądanym efektem, a nawet prawdziwą sztuką. W tym kontekście celem jest utrudnienie, a najlepiej całkowite uniemożliwienie osobom trzecim zrozumienia, co dany program robi i w jaki sposób. Obfuskacja czy też zaciemnianie kodu, czyli świadome zawiłe pisanie, staje się pożądaną strategią, a nie wadą.
Przykład uwikłanego kodu w C wypisującego liczby pierwsze mniejsze niż 100.
_(__,___,____){___/__<=1?_(__,___+1,____):!(___%__)?_(__,___+1,0):___%__==___/ __&&!____?(printf(„%d\t”,___/__),_(__,___+1,0)):___%__>1&&___%__<___/__?_(__,1+ ___,____+!(___/__%(___%__))):___<__*__?_(__,___+1,____):0;}main(){_(100,0,0);}
Ideałem jest tzw. obfuskacja typu black box. Oznacza ona sytuację, w której o programie nie da się dowiedzieć niczego poza tym, co sam jawnie ujawnia. Dla prostego przykładu – jeśli aplikacja przyjmuje dwie liczby i zwraca ich sumę, łatwo domyślić się, jaki jest jej efekt. W przypadku idealnej obfuskacji nie byłoby jednak możliwe ustalenie, w jaki sposób program ten wynik osiąga. Analiza kodu, dekompilacja, śledzenie wykonania czy obserwacja kanałów bocznych nie dawałyby żadnego wglądu w jego wewnętrzną logikę.
W praktyce takie podejście jest szczególnie istotne w systemach przetwarzających dane wrażliwe – na przykład w finansach, wojskowości czy infrastrukturze krytycznej. Program, którego struktury i mechanizmów nie da się odtworzyć, nie pozostawia realnej powierzchni ataku. Jeśli nie da się zrozumieć, jak działa, nie da się też łatwo obejść jego zabezpieczeń.
Nie ma nic idealnego
Niestety idea idealnej obfuskacji w praktyce okazuje się nieosiągalna. Wielu badaczy próbowało się do niej zbliżyć i momentami było bardzo blisko, jednak obecny stan wiedzy sugeruje jedno – nie da się stworzyć programu, który działa niezawodnie na komputerze, a jednocześnie pozostaje całkowicie nieprzenikniony dla człowieka. Zawsze da się coś wywnioskować poprzez obserwację działania, analizę zachowania czy odpowiednio dobrane testy. Na szczęście, obfuskacja nierozróżnialna może być równie skuteczna w praktyce jak obfuskacja doskonała.
W tym podejściu program po zaciemnieniu staje się nierozróżnialny od innych programów realizujących dokładnie to samo zadanie. Innymi słowy, jeśli dwa różne programy wykonują tę samą funkcję, to po obfuskacji ich kodów źródłowych nie da się już ustalić, który kod odpowiada któremu plikowi binarnemu. To bardzo cenna właściwość, bo pozwala na przykład bezpiecznie zaszyć w programie wrażliwe dane – hasła, klucze kryptograficzne czy inne poufne informacje – bez realnego ryzyka ich wydobycia.
Potencjalni napastnicy nie poprzestają dziś jednak tylko na analizie samego oprogramowania – coraz częściej biorą na warsztat również fizyczne elementy. Od dekonstruowania układów ASIC i SoC warstwa po warstwie, po wyciąganie danych z układów FPGA – front walki przeniósł się też głęboko w obszar sprzętu. Na szczęście istnieją wyjątkowo pomysłowe techniki obfuskacji hardware’u, które potrafią skutecznie odwrócić role i mocno utrudnić takie działania. W połączeniu z technikami software’owymi stanowią naprawdę dobrą warstwę zabezpieczeń.
Sposobów jest mnóstwo i zależą one w dużej mierze tylko od kreatywności twórców. Jednym z ciekawszych przykładów jest technika związana z FPGA, znana jako LifeLine CrossTalk Obfuscation. Działa ona na poziomie routingu i wykorzystuje fizyczną bliskość długich ścieżek połączeń, które nie są formalnie połączone w netliście. Dzięki temu możliwe jest tworzenie ukrytych kanałów komunikacyjnych. Nawet jeśli atakujący zdobędzie netlistę, nie zobaczy tych ukrytych zależności. A ich odszukanie, a następnie zrozumienie może wymagać olbrzymiego nakładu pracy. Zaczynamy mówić powoli o możliwościach państw i największych firm technologicznych, a nie o zbłąkanym hakerze.
Kolejnym z ciekawych sposobów ochrony układów jest zaciemnianie maszyn stanów skończonych (FSM) już na poziomie bramek, po tym jak synteza logiki wygeneruje netlistę. W praktyce można tu zastosować różne zabiegi: dodawać fikcyjne stany, aby sztucznie zwiększyć ich przestrzeń, kodować stany w nieprzewidywalny sposób, wprowadzać przejścia, które są nieosiągalne lub celowo mylące, a także rozpraszać elementy przechowujące stan po całym projekcie. Ponieważ analiza sposobu sterowania układem zdradza bardzo wiele informacji o jego działaniu, utrudnianie rekonstrukcji FSM-ów jest szczególnie skuteczną formą obfuskacji. W dodatku bardzo kosztowną do rozszyfrowania.
Chociaż obfuskacja nie jest sposobem idealnym, stanowi świetne zabezpieczenie. Jej pokonanie jest czasochłonne oraz wymaga dużych nakładów finansowych. Jeśli nie istnieje sposób na stuprocentowe bezpieczeństwo, to skuteczne odstraszenie napastnika jest z pewnością drugą najlepszą dostępną opcją.