W świecie aplikacji webowych API pełnią rolę kręgosłupa komunikacji między różnymi systemami. Niestety, każdy otwarty endpoint API to potencjalny wektor ataku. Niezabezpieczone API może prowadzić do poważnych naruszeń, od nieautoryzowanego dostępu po wycieki danych. W tym artykule przybliżę Ci kluczowe metody zabezpieczania API w ASP.NET Core, dzięki którym ograniczysz ryzyko ataków i upewnisz się, że Twoje usługi są chronione przed niepożądanymi gośćmi.
Uwierzytelnianie i autoryzacja
Absolutną podstawą bezpieczeństwa API jest uwierzytelnianie (sprawdzenie tożsamości klienta) oraz autoryzacja (kontrola uprawnień). W praktyce oznacza to tyle, że każdy wrażliwy endpoint powinien wymagać poprawnych poświadczeń i nadawać dostęp tylko uprawnionym użytkownikom. W ASP.NET Core służy do tego atrybut [Authorize], który zastosowany na kontrolerze lub akcji powoduje, że dostęp uzyskają wyłącznie uwierzytelnieni klienci (np. posiadający prawidłowy token JWT).
Najpopularniejszym podejściem w API jest dziś uwierzytelnianie tokenowe, na przykład przy użyciu JWT (JSON Web Token). Token JWT to zaszyfrowany znacznik zawierający informacje o użytkowniku i jego uprawnieniach, dołączany do każdego żądania. Dzięki temu API może zweryfikować podpis tokenu i ustalić, czy klient jest kimś, komu wolno wykonać dane operacje. Alternatywnie, w bardziej rozbudowanych scenariuszach stosuje się OAuth2/OpenID Connect (np. Azure AD, IdentityServer) do delegowania uwierzytelniania zewnętrznemu dostawcy. Dla prostszych przypadków wewnątrz organizacji można też wykorzystywać API Keys (statyczne klucze dostępu), pamiętając jednak, że same klucze łatwo skopiować, więc najlepiej łączyć je z innymi mechanizmami (np. ograniczeniem uprawnień klucza).
Po pomyślnym uwierzytelnieniu należy zadbać o autoryzację dostępu do konkretnych zasobów. ASP.NET Core pozwala na wygodne definiowanie ról i polityk. Przykładowo, jeśli dany endpoint ma być dostępny tylko dla administratorów, można to zapisać w kodzie poprzez atrybut z rolą:
[Authorize(Roles = "Admin")]
public IActionResult GetSensitiveData() { ... }Taki zapis sprawi, że metoda GetSensitiveData() będzie dostępna wyłącznie dla użytkowników należących do roli Admin. W podobny sposób da się tworzyć polityki autoryzacji oparte na claimach użytkownika (np. wymaganie zweryfikowanego adresu email lub spełnienia innego warunku). Kluczowe jest, by każdy chroniony zasób w API miał przypisane odpowiednie wymagania. Dzięki temu nawet jeśli ktoś zdobędzie token lub cookie uwierzytelniające, nie uzyska dostępu do funkcjonalności, do których nie ma uprawnień.
Wskazówka: W aplikacjach typu SPA korzystających z ASP.NET Core można użyć Identity i uwierzytelniania na bazie cookie dla przeglądarki lub tokenów JWT dla klienta mobilnego czy zewnętrznego. Cookies są o tyle wygodne, że przeglądarka obsługuje je automatycznie (HttpOnly, SameSite), ale gdy korzystasz z tokenów, musisz sam zadbać o ich bezpieczne przechowywanie po stronie klienta.
Szyfrowana komunikacja (HTTPS)
Drugi fundament bezpieczeństwa to szyfrowanie ruchu sieciowego. Wszystkie komunikaty między klientem a API powinny odbywać się wyłącznie po HTTPS. HTTPS (protokół HTTP z TLS) zapewnia, że dane przesyłane w żądaniach i odpowiedziach są zaszyfrowane, co chroni przed ich przechwyceniem lub modyfikacją po drodze. W praktyce w ASP.NET Core wystarczy włączyć przekierowanie na HTTPS oraz HSTS w konfiguracji aplikacji. Domyślne szablony projektów już to oferują. Metoda app.UseHttpsRedirection(); automatycznie przekieruje każde przychodzące żądanie HTTP na bezpieczny URL HTTPS. Dodatkowo zaleca się włączenie HSTS, czyli HTTP Strict Transport Security, aby informować przeglądarki, że nasz serwis zawsze używa TLS. W efekcie nawet pierwsze żądanie (lub link HTTP) zostanie wewnętrznie zamienione na HTTPS bez wysyłania w ogóle po niezabezpieczonym protokole. HSTS wymusza u klienta korzystanie z HTTPS na stałe, minimalizując ryzyko ataków typu man-in-the-middle.
Pamiętaj, aby zainstalować poprawny certyfikat SSL dla swojej domeny (można to łatwo uzyskać np. przez Let's Encrypt) i regularnie go odnawiać. ASP.NET Core ułatwia to zadanie, możesz skorzystać z wbudowanych mechanizmów Kestrel do obsługi certyfikatów. Dzięki pełnemu szyfrowaniu komunikacji atakujący nie podsłucha ani nie podejrzy wymienianych danych (np. tokenów czy danych osobowych) w trakcie transmisji.
Walidacja danych i ochrona przed atakami
Kolejną warstwą zabezpieczeń jest walidacja i sanityzacja danych wejściowych. Zasadą numer jeden jest: nigdy nie ufaj danym pochodzącym od użytkownika (ani zewnętrznego klienta API). Każdy parametr żądania, nagłówek czy ciało JSON może zawierać niepożądane lub złośliwe treści. Dlatego zawsze sprawdzaj, czy dane mają oczekiwany format, typ i zakres wartości. ASP.NET Core wspiera to poprzez Model Validation, możesz użyć atrybutów jak [Required], [StringLength], [Range] w definicjach swoich modeli, aby ramy MVC automatycznie odrzuciły nieprawidłowe dane jeszcze zanim trafią do logiki aplikacji.
Przykładowo:
public class UserModel
{
[Required]
[StringLength(100, MinimumLength = 3)]
public string Name { get; set; }
[Range(18, 100)]
public int Age { get; set; }
}Ponadto warto sanityzować dane, np. usuwać lub neutralizować fragmenty mogące stanowić atak. Dotyczy to zwłaszcza tekstu HTML/JavaScript przekazywanego do aplikacji. Jeśli Twoje API przetwarza lub zwraca jakieś HTML (np. w szablonach email), rozważ użycie bibliotek typu AntiXSS do oczyszczenia niebezpiecznych znaczników.
Najczęstsze wektory ataku na API to m.in. SQL Injection oraz Cross-Site Scripting (XSS). Przed SQL Injection obronisz się, stosując parametryzowane zapytania do bazy danych albo korzystając z ORM (np. Entity Framework Core), który domyślnie parametryzuje zapytania. Dzięki temu nawet jeśli użytkownik przekaże w parametrze złośliwy fragment SQL, nie zostanie on wykonany na bazie. Z kolei przed XSS uchronisz aplikację poprzez filtrowanie/enkodowanie danych wyjściowych, choć w przypadku API, które zwraca głównie JSON, ryzyko XSS dotyczy raczej front-endu korzystającego z API. Niemniej nie przesyłaj w responsie niesprawdzonych skryptów ani HTML pochodzących od innych użytkowników.
Warto również zabezpieczyć się przed CSRF (Cross-Site Request Forgery), zwłaszcza jeśli API korzysta z uwierzytelnienia opartego o cookie i jest używane przez aplikację front-end (np. SPA). CSRF polega na tym, że ofiara zalogowana do Twojej aplikacji może nieświadomie wykonać żądanie do API (np. poprzez obrazek lub skrypt na zewnętrznej stronie). Aby temu zapobiec, wymagaj tokenów anty-CSRF przy operacjach zmieniających stan (POST, PUT, DELETE). ASP.NET Core oferuje gotowe mechanizmy Anti-Forgery, wystarczy je włączyć i dołączać wygenerowany token (np. w nagłówku lub jako ukryte pole) w żądaniach modyfikujących dane. Dodatkowo upewnij się, że cookie sesyjne/tokenowe mają ustawiony flagi SameSite=Lax/Strict, co ograniczy ich wysyłanie w cross-site requestach.
Ochrona przed nadużyciami (Rate limiting i CORS)
Nawet prawidłowo uwierzytelnione API może paść ofiarą nadużyć, np. brute force (masowe odgadywanie danych logowania), DDoS (próba przeciążenia serwera) czy innych form spamowania zapytaniami. Dlatego kolejnym elementem obrony jest rate limiting, czyli ograniczanie liczby żądań, jakie dany klient może wysłać w określonym czasie. W .NET 7+ mamy wbudowane middleware do limitowania ruchu, które pozwala np. ustalić maksymalną liczbę zapytań na minutę na IP lub użytkownika. Dzięki temu utrzymujemy ruch na bezpiecznym poziomie, a nadmiarowe żądania są odrzucane zanim zdążą obciążyć naszą aplikację. Można też skorzystać z gotowych pakietów (np. AspNetCoreRateLimit dla starszych wersji .NET) lub zaimplementować własne ograniczenia (np. poprzez zliczanie żądań w pamięci czy bazie i zwracanie statusu HTTP 429 Too Many Requests po przekroczeniu limitu).
Kolejną kwestią jest CORS (Cross-Origin Resource Sharing). Jeżeli z Twojego API korzystają aplikacje działające pod innymi domenami (np. front-end SPA na osobnym hostingu), powinieneś jawnie określić politykę CORS, aby kontrolować, które źródła (domeny) mogą wysyłać zapytania do API. Brak konfiguracji CORS oznacza domyślne blokowanie takich żądań przez przeglądarki, z kolei ustawienie zbyt liberalne (AllowAnyOrigin) może otworzyć dostęp do API z dowolnej strony, a to bywa niepożądane. Najlepiej ograniczyć dostęp tylko do zaufanych domen (np. własnej aplikacji klienckiej) i tylko potrzebnych metod/headers. W ASP.NET Core zrobisz to dodając odpowiednią politykę w Startup.cs/Program (metodą AddCors i UseCors). Przykładowo możesz dopuścić wyłącznie swoją domenę produkcyjną, wszystkie nagłówki i metody HTTP:
services.AddCors(options =>
{
options.AddPolicy("AllowMyApp",
builder => builder.WithOrigins("https://moja-aplikacja.pl")
.AllowAnyHeader()
.AllowAnyMethod());
});Taka konfiguracja upewni się, że skrypty z nieautoryzowanych źródeł nie będą mogły wykonać zapytań do Twojego API na dane uwierzytelnionego użytkownika.
Na koniec, monitoruj i loguj ruch przychodzący do API. Dobre logowanie prób dostępu (zwłaszcza nieudanych logowań, błędów autoryzacji czy podejrzanych parametrów) pozwoli Ci szybciej wykryć próby ataków. W razie incydentu, logi ułatwią analizę, które endpointy były na celowniku i jakie dane próbowano pozyskać. Rozważ też ustawienie alarmów lub limitów na nietypowe wzorce ruchu (np. nagły skok żądań), by móc zareagować zanim atak wyrządzi szkody.
Podsumowanie
Bezpieczne API to rezultat świadomego stosowania wielu warstw ochrony. Podsumowując: wymuszaj uwierzytelnienie i stosuj autoryzację na każdym wrażliwym endpointzie, szyfruj ruch (HTTPS) od pierwszego do ostatniego bajtu, waliduj dane wejściowe i chroń się przed typowymi atakami (XSS/SQLi/CSRF itp.), a także kontroluj ruch (CORS, rate limiting) i reaguj na podejrzane aktywności. Dzięki tym zasadom znacząco utrudnisz zadanie potencjalnemu napastnikowi, a użytkownikom zapewnisz ochronę ich danych.
Jeśli chcesz zgłębić temat zabezpieczania aplikacji webowych w .NET, zachęcam do sprawdzenia mojego szkolenia online: Szkoła Bezpieczeństwa w C#/.NET. To kompletny, praktyczny trening, w którym pokazuję krok po kroku jak tworzyć bezpieczne aplikacje w ASP.NET Core - od obrony przed najczęstszymi atakami (SQL Injection, XSS, CSRF, DDoS, Brute Force i inne) po wdrażanie najlepszych praktyk bezpieczeństwa. Bezpieczeństwo to inwestycja, która szybko się opłaca, zadbaj o nie już na etapie developmentu, bo jak głosi klasyczna zasada: lepiej zapobiegać niż leczyć.