Kilka zdań do chatu i aplikacja gotowa — to właśnie jest vibe coding. Problem zaczyna się wtedy, gdy ta aplikacja trafia do prawdziwych użytkowników, a kilka dni później okazuje się, że ktoś pobrał całą bazę danych.
Dlaczego tak się dzieje? AI tworzy kod, który działa — ale nie kod, który jest bezpieczny. To nie wada modeli. To po prostu konsekwencja tego, o co je prosisz.
Najważniejsze wnioski
- AI pisze kod, który działa. Nie pisze kodu, który jest bezpieczny — to są dwie różne rzeczy.
- AI generuje zapytania do bazy bez sprawdzenia, czyje dane zwraca. Zalogowany użytkownik może zobaczyć dane innego — wystarczy zmienić jeden parametr.
- Funkcje serwerowe w Next.js są dostępne z internetu. Można je wywołać bez otwierania Twojej strony.
- Token sesji trzymany w przeglądarce jak hasło w Notatniku — każda wtyczka i biblioteka może go odczytać.
- Brak limitu wielkości zapytania, brak weryfikacji płatności — AI tego nie dodaje. Atakujący to wie.
Dlaczego AI pomija bezpieczeństwo?
Kiedy piszesz „dodaj logowanie”, AI ma jeden cel: żeby logowanie działało. I działa. Ale programiści wiedzą, że wokół każdej funkcji powinny być dodatkowe zabezpieczenia: sprawdzanie, czy użytkownik naprawdę ma dostęp, izolacja danych różnych klientów, blokada nadmiernego ruchu.
AI tego nie dodaje, bo nikt go o to nie poprosił. Efekt: aplikacja działa — ale jest otwarta dla każdego, kto wie, gdzie szukać.
Poniżej opisuję cztery miejsca, gdzie ta luka pojawia się najczęściej.
1. Baza danych jako otwarty sejf
NeonDB i podobne serwisy serverless PostgreSQL działają inaczej niż Supabase — połączenie z bazą odbywa się wyłącznie po stronie serwera, przez tajny ciąg połączeniowy (connection string), który nigdy nie powinien trafić do przeglądarki. To dobrze. Problem leży gdzie indziej.
Gdy AI generuje kod API lub funkcje serwerowe, tworzy zapytania do bazy — ale często bez sprawdzenia, czyje dane ma zwrócić. Zapytanie SELECT * FROM orders WHERE id = $1 zwróci zamówienie o podanym ID komukolwiek, kto wywoła endpoint i poda dowolne ID. Zalogowany użytkownik może w ten sposób przeglądać dane innych użytkowników — wystarczy zmienić jeden parametr w żądaniu.
AI pisze kod, który działa dla prawidłowego przepływu: użytkownik klika „moje zamówienia” i widzi swoje. Że inny użytkownik może podać cudze ID i też to zobaczyć — tego AI nie sprawdza, bo dostał tylko polecenie „pokaż zamówienie”.
Rozwiązanie to jedno dodatkowe warunki w każdym zapytaniu: WHERE id = $1 AND user_id = $2 — gdzie drugi parametr pochodzi z sesji serwera, nie z żądania użytkownika. PostgreSQL oferuje też wbudowany mechanizm Row-Level Security (RLS), który wymusza taką izolację na poziomie samej bazy, niezależnie od tego, co napisze programista.
Jest też kwestia connection string — ciągu znaków z hasłem do bazy. Jeśli przypadkowo trafi do repozytorium Git, zostanie osadzony w kodzie klienta lub pojawi się w logach — baza jest otwarta dla każdego, kto go znajdzie. AI, generując przykłady kodu, czasem wkleja connection string bezpośrednio w kodzie zamiast odwoływać się do zmiennej środowiskowej.
2. Funkcje serwerowe — wejście bez drzwi
W nowoczesnych frameworkach (jak Next.js) można pisać kod, który wykonuje się na serwerze, a wygląda jak zwykła funkcja w pliku. Problem: ta funkcja jest w rzeczywistości dostępna z internetu jak każda strona www.
Co to oznacza? Ktoś nie musi w ogóle otwierać Twojej aplikacji w przeglądarce. Może wysłać żądanie bezpośrednio do tej funkcji z własnego skryptu, podając wymyślone dane. Jeśli w środku nie ma sprawdzenia, kto pyta — system wykona polecenie.
AI pisze kod działający wtedy, gdy uprawniony użytkownik kliknie przycisk. Że tę samą funkcję można wywołać bez przycisku i bez logowania — tego AI nie bierze pod uwagę.
Dobra ochrona wymaga trzech rzeczy:
- Walidacja danych — odrzucenie wszystkiego, co nie wygląda jak oczekiwane dane, zanim cokolwiek zostanie wykonane
- Sprawdzenie tożsamości — każda funkcja sprawdza, czy pytający użytkownik rzeczywiście ma prawo to zrobić
- Sprawdzenie własności — czy ten użytkownik jest właścicielem zasobu, który chce zmodyfikować (nie tylko czy jest zalogowany)
Dodatkowe ryzyko: kod serwerowy czasem przypadkowo przesyła do przeglądarki dane, które nie powinny nigdy wyjść z serwera — np. zaszyfrowane hasła z bazy danych.
3. Sesja — klucz zostawiony w widocznym miejscu
Kiedy prosisz AI o „dodaj logowanie”, najczęstszy wynik to przechowywanie tokenu sesji (klucza do konta) w lokalnej pamięci przeglądarki. Prosto i działa — ale to jedno z najczęstszych źródeł kradzieży kont.
Każdy skrypt działający na Twojej stronie może odczytać tę pamięć. Nie tylko Twój kod — każda zewnętrzna biblioteka, każdy widget czatu, każda zależność zainstalowana przez kogoś innego. Skrypt odczytuje klucz, wysyła go gdzieś dalej — i od tej chwili atakujący może działać jako Twój użytkownik.
Rozwiązanie to zapisanie tego klucza w pliku cookie z opcją httpOnly. Taki plik cookie jest dla skryptów całkowicie niewidoczny — żaden kod na stronie nie może go odczytać, tylko serwer.
Kolejna kwestia to czas ważności sesji. Jeśli klucz sesji jest ważny 24 godziny, a ktoś go przechwyci — ma 24 godziny pełnego dostępu. Skrócenie czasu ważności i regularne odświeżanie sesji znacznie zmniejsza okno, w którym przejęty klucz jest użyteczny.
Przy okazji: sposób, w jaki przechowujesz hasła w bazie, też ma znaczenie. Przestarzałe ustawienia haszowania (przekształcania hasła w bezpieczny ciąg znaków) mogą sprawić, że po wycieku bazy hasła da się odtworzyć w rozsądnym czasie.
4. Serwer oblężony przez boty
Twój serwer, jak każdy, obsługuje żądania jedno po drugim. Wyobraź sobie kasę w sklepie — obsługuje jedną osobę na raz, reszta czeka. Jeśli ktoś zajmie tę kasę na bardzo długo — wszyscy stoją.
Bez limitu wielkości przesyłanych danych, atakujący może wysłać na serwer plik o rozmiarze 100 MB. Serwer musi go przetworzyć zanim odrzuci — a to może zająć kilka sekund, podczas których nie obsługuje nikogo innego. Jeden atak blokuje wszystkich użytkowników. Kilka linii konfiguracji wystarczy, żeby tego uniknąć — AI ich domyślnie nie dodaje.
Webhooki (automatyczne powiadomienia od zewnętrznych usług, np. Stripe wysyłający informację o płatności) to też częsty słaby punkt. Bez weryfikacji, czy powiadomienie naprawdę przyszło od Stripe, każdy może wysłać fałszywe zdarzenie — np. „płatność zaakceptowana” — i dostać dostęp do produktu bez płacenia.
Co z tym zrobić?
Każde z tych zabezpieczeń z osobna nie jest skomplikowane. Trudne jest wdrożenie ich wszystkich, spójnie, bez pominięcia żadnego. Od tego jest checklista — i agent AI, który może ją wykonać punkt po punkcie.
Zasada jest prosta: każda część systemu musi bronić się sama, niezależnie od innych. Baza danych sama kontroluje, kto widzi które dane. Każda funkcja serwerowa sama sprawdza, czy pytający ma prawo. Żadne dane nie trafiają dalej, zanim nie zostaną zweryfikowane.
FAQ
Czy to dotyczy też małych projektów?
Tak. Zautomatyzowane skrypty skanujące internet nie rozróżniają małych i dużych serwisów — szukają niezabezpieczonych endpointów i błędów w autoryzacji niezależnie od skali projektu.
Czy NeonDB jest niebezpieczny?
Nie — to standardowy PostgreSQL i dobrze zaprojektowany serwis. Ale baza danych sama z siebie nie wie, który użytkownik powinien widzieć które dane. To programista (lub agent AI z odpowiednią checklistą) musi dodać odpowiednie warunki do każdego zapytania.
Czy AI zepsuje mi kod, jeśli zlecę mu poprawki bezpieczeństwa?
Nie, jeśli dasz mu precyzyjne instrukcje. Ten sam model, który pominął zabezpieczenia przy tworzeniu aplikacji, perfekcyjnie je wdroży, jeśli dostanie checklistę z dokładnymi krokami. Poniżej jest właśnie taka checklista.
Czy muszę rozumieć kod, żeby to wdrożyć?
Nie musisz go pisać — od tego jest agent AI. Musisz rozumieć, czego chcesz, żeby ocenić czy agent wykonał zadanie poprawnie. Ten artykuł daje Ci właśnie to rozumienie.
Plik implementacyjny dla agenta
Opisane problemy przekładają się na 50 konkretnych zadań pogrupowanych w pięciu etapach:
- Baza danych — włączenie ochrony, optymalizacja reguł dostępu, wymuszenie izolacji danych
- Funkcje serwerowe — walidacja danych, sprawdzanie tożsamości, ochrona przed nieautoryzowanym dostępem
- Sesja i logowanie — bezpieczne przechowywanie sesji, odporność na przejęcie konta, silne haszowanie haseł
- Serwer i webhooki — limity ruchu, ochrona przed przeciążeniem, weryfikacja płatności
- Infrastruktura — skaner podatności, zapora aplikacyjna, Zero Trust
Każde zadanie zawiera gotowy przykład kodu i sposób sprawdzenia, czy działa.