Xamarin-bezpieczeństwo

Xamarin – bezpieczeństwo kodu. Jak chronić się przed niepowołanym dostępem?

Bezpieczeństwo aplikacji staje się kluczowe dopiero wtedy, gdy zadaniem jest gromadzenie i przesyłanie wrażliwych danych np.: w aplikacjach bankowych, sklepach itp. Mniejsze projekty najczęściej pomijają tę kwestię. Skupiamy się głównie na tym, aby dostarczyć rozwiązania rozbudowane funkcjonalnie, o przejrzystym, intuicyjnym interfejsie i miłej dla oka szacie graficznej. Niestety jest to poważny błąd, który naraża naszą aplikację na różnego rodzaju niebezpieczeństwa. Warto zatem mieć świadomość tego, co tak naprawdę udostępniamy innym i jak sprawić, aby nasz kod pisany w Xamarin nie dostał się w niepowołane ręce.

 

Jakie są zagrożenia?

Mogłoby się wydawać, że po skompilowaniu, podpisaniu i wrzuceniu aplikacji do sklepu nic nam nie grozi. Niestety, ale w przypadku platformy Xamarin tak nie jest. Jeżeli w naszym projekcie korzystamy z bibliotek PCL, to po skompilowaniu, zarówno na platformę Android i iOS, bez większych trudów możemy przejrzeć zawartość takiej paczki. W przypadku platformy Android, wystarczy rozpakować plik .APK. To samo tyczy się platformy iOS i jej paczki .IPA. Wszelkie algorytmy, logika, mechanizmy, klasy, ich zawartości, jak również zasoby dołączane jako EmbeddedResource są tutaj widoczne jak na dłoni i mogą one pozwolić komuś na oszukanie naszego programu.

 

Załóżmy, że korzystamy z narzędzi, które służą do analityki. Najczęściej wymagają one od nas klucza, na podstawie którego jesteśmy identyfikowani i dzięki któremu wszystkie zebrane dane statystyczne trafiają właśnie na nasze konto. Taki klucz najczęściej przechowujemy w pliku konfiguracyjnym. Jeżeli ktoś dobierze się do niego, to bez problemu będzie mógł wysyłać nam różne informacje i w ten sposób zaśmiecać naszą analitykę. To tylko jeden z możliwych scenariuszy. A co, gdy ktoś uzyska w ten sposób dostęp do bazy danych, do której łączymy się bezpośrednio z poziomu aplikacji? Szkody mogą być wtedy jeszcze bardziej dotkliwe.

 

Jak można tego uniknąć?

Nie można, a przynajmniej nie w 100%. Możemy za to utrudnić zadanie wścibskim osobom i je tym samym zniechęcić. Z pomocą przychodzi nam tutaj obfuskacja kodu. Obfuskacja jest to technika stosowana w programowaniu, która polega na tzw. „zaciemnianiu” kodu. Chodzi generalnie o to, aby kod po kompilacji nie był łatwy do odczytania przez nieupoważnione osoby.

 

Nie będę tutaj opisywał na czym dokładnie polega sam mechanizm obfuskacji. Nie chcę też, aby artykuł ten dotyczył procesu instalacji i konfiguracji różnych gotowych narzędzi. Jeżeli pracujemy na platformie Windows, to mamy ułatwione zadanie bo jest ich wiele. Wartymi polecenia są na pewno Babel i Dotfuscator. Pozwalają one zautomatyzować cały proces, są na rynku od dłuższego czasu, udostępniają pluginy do środowiska Visual Studio i posiadają rozbudowaną dokumentację. Jedynym minusem jest to, że nie działają z poziomu MacOS.

 

Ale ja pracuję na MacOS. Czy to znaczy, że mój kod nie będzie bezpieczny?

Na szczęście nie. Jest szereg możliwości, które pozwolą nam zabezpieczyć aplikację na systemach z nadgryzionym jabłkiem i o nich chciałbym właśnie napisać. Metody te można oczywiście też zastosować na platformie Windows, jako pierwsza warstwa zabezpieczenia kodu.

 

Przechodząc do meritum, wszystko co zamieszczamy w projektach iOS i Android możemy w pewnym stopniu ukryć. Jest to możliwe dzięki skompilowaniu do kodu natywnego. Taki kod dalej można odczytać, ale wymaga to więcej wiedzy oraz lepszych narzędzi. Jak zatem możemy skompilować do kodu natywnego? W przypadku iOS jest to robione od ręki. Nie musimy zaznaczać żadnych dodatkowych ustawień w opcjach kompilatora.

 

Inaczej sytuacja wygląda na platformie Android. Tam musimy zaznaczyć pole „Embed assemblies in native code”. Opcja ta jest dostępna tylko w wersji Enterprise środowiska Visual Studio. Dodatkowo na platformie Android możemy skorzystać z narzędzia ProGuard. Służy ono do zmniejszenia rozmiaru wygenerowanej paczki, a także obfuskacji kodu. Jego działanie polega na zmianie nazw klas, metod, pól co sprawia je trudniejszymi do odczytania dla człowieka. W przypadku ProGuard należy pamiętać o prawidłowym skonfigurowaniu tego narzędzia. Chodzi tutaj o dodanie odpowiednich reguł, na podstawie których będzie on obfuskował zawartość odpowiednich przestrzeni nazw. Więcej na ten temat można się dowiedzieć z dokumentacji ProGuard.

 

 

Jakie dobre praktyki warto stosować?

  • Upewnij się, że nie przechowujesz żadnych ważnych informacji w plikach, które są budowane jako EmbeddedResource. Są to najczęściej pliki XML. Zostaną one skopiowane do biblioteki i kompilacja do kodu natywnego ich niestety nie ukryje.
  • Jeżeli musisz przechowywać w aplikacji dane dostępowe, klucze, seedy itp. to staraj się to robić w klasach w projektach platformowych. Nie musisz dwa razy pisać takiej klasy. Wystarczy, że stworzysz ją raz i skopiujesz z opcją linkowania pliku. Dzięki temu zostanie ona dołączona do projektu platformowego i skompilowana do kodu natywnego. Jej zawartość będzie niewidoczna po rozpakowaniu paczki aplikacji.
  • Jeżeli jesteś zmuszony do przechowywania wrażliwych danych w aplikacji, to nawet stosując się do powyższego punktu nie przechowuj ich w postaci surowej. Nawet prosty mechanizm szyfrowania pozwoli Ci dodatkowo zabezpieczyć je przed dostępem niepowołanych osób.
  • Jeżeli jest taka możliwość, to ogranicz przechowywanie wszelkich kluczy w aplikacji. Pomocne może w tym być pobieranie konfiguracji przy pierwszym żądaniu do API. Należy pamiętać o tym, aby komunikacja z serwerem była zaszyfrowana, aby nikt nie uzyskał tych danych po prostym zapytaniu do serwera.
  • Nie wierz w pełni temu co tutaj napisałem. Może to głupie i strzelam sobie w stopę, ale najwięcej nauczysz się samemu zaglądając do swojej aplikacji. Przed wrzuceniem paczki do sklepu zabaw się w hackera. Spróbuj ją rozpakować, zobacz co jest w środku. Masz ułatwione zadanie bo sam najlepiej wiesz czego szukać. Znajdź to i przekonaj się co będą mogli zobaczyć też inni. Póki sam tego nie zrobiłem to żyłem w nieświadomości jak wiele ważnych informacji dostępnych było dla innych. Być może przedstawione tutaj metody i mechanizmy nie będą skutecznym rozwiązaniem Twojego problemu, ale lepiej mieć tego świadomość i poszukać, niż potem rwać włos z głowy, gdy ktoś wykorzysta to przeciwko Tobie.

 

Co jeszcze powinienem wiedzieć?

Bardzo dużo napisałem tutaj o tym jak się zabezpieczyć przed tym, gdy ktoś podejrzy zawartość naszej paczki, a nie napisałem nic o tym, w jaki sposób miałby ją w ogóle zdobyć. Wydawałoby się, że pobierając je ze sklepu AppStore czy Google Play jest to niemożliwe. Realia są jednak zupełnie inne. Dopiero od niedawna Apple zablokowało możliwość instalowania plików .IPA za pomocą iTunes. Dalej jest to jednak możliwe z poziomu Xcode. Pobierając aplikację ze sklepu jest ona przechowywana w przestrzeni tymczasowej na czas instalacji. Mając odblokowany telefon (tzw. Jailbreak) możemy taką paczkę z niego wyciągnąć. Jest to jeszcze prostsze w przypadku Androida. Tam mamy pełny dostęp do telefonu, a także karty SD, na której możemy instalować aplikacje, zatem dostęp do paczki jest bardzo prosty.

 

Podsumowanie.

Temat bezpieczeństwa nigdy nie będzie w 100% wyczerpany. Problemów jak i ich rozwiązań jest mnóstwo. Najważniejsza jest świadomość zagrożeń, które mogą nas spotkać. Warto zatem się przed nimi zabezpieczyć chociażby w minimalnym stopniu. Jak pokazałem w tym artykule, nie jest to wcale takie trudne. Niewielkie zmiany mogą wprowadzić ogromną różnicę. Mam nadzieję, że w kolejnym projekcie temat bezpieczeństwa nie będzie już dla Ciebie tylko dodatkowym etapem w procesie wytwarzania oprogramowania, a punktem wyjściowym, który podyktuje kierunek jaki obierzesz już na etapie projektowania architektury.

 

Jeśli masz jakieś inne ciekawe doświadczenia z obfuskowaniem kodu to zapraszam do dyskusji.