MVP DevelopmentMVP Development
Powrót do zasobów

Jak zapobiegać prompt injection: zabezpieczenia dla realnej aplikacji LLM

9 min minimalny czas czytania
How to Prevent Prompt Injection: Guardrails for a Real LLM App

Wdrażasz funkcję LLM, która czyta cokolwiek, czego w pełni nie kontrolujesz: wiadomość użytkownika, dokument, stronę internetową pobraną przez narzędzie, i tym samym otwierasz kanał, do którego może pisać atakujący. Prompt injection to tekst docierający przez ten kanał, który próbuje przejąć instrukcje modelu zamiast odpowiadać na zadane pytanie. Ten przewodnik pokazuje, jak zapobiegać prompt injection za pomocą zabezpieczeń, które sprawdzają się, gdy twoją aplikację zaleje prawdziwy ruch. Żadne z nich nie czyni modelu w pełni odpornym. Wielowarstwowa obrona podnosi koszt ataku na tyle, że większość atakujących przechodzi do łatwiejszego celu.

Czym jest prompt injection

Aplikacja LLM działa tak, że przekazuje modelowi prompt: instrukcje systemowe napisane przez twój zespół plus wszystko inne, co dociąga zapytanie, czyli wiadomość użytkownika, akapit dokumentu, wynik wcześniejszego wywołania narzędzia. Model przewiduje kolejny fragment tekstu na podstawie tego wszystkiego naraz, czytając instrukcje i pobrany tekst jako jeden ciągły strumień tokenów. Nic nie oznacza jednej części jako zaufanej instrukcji, a drugiej jako niezaufanych danych. Prompt injection to niezaufany tekst skonstruowany tak, by został odczytany jako instrukcja, a nie jako treść do podsumowania czy pytanie, na które trzeba odpowiedzieć. E-mail w skrzynce supportowej, który każe czytającemu go modelowi ujawnić dane konta, których nie powinien ujawniać. Linijka na zeskrapowanej stronie internetowej, która każe agentowi badawczemu pominąć kontrolę, którą miał wykonać. Sformułowania wciąż się zmieniają. Wzorzec pozostaje ten sam: treść, której model nie powinien był posłuchać, zostaje wykonana mimo to, bo model nie ma wbudowanego sposobu odróżnienia instrukcji od danych.

Bezpośrednie i pośrednie ataki prompt injection

Bezpośredni prompt injection to prostszy przypadek: ktoś wpisuje coś w twoim interfejsie czatu, próbując obejść jego instrukcje, prosząc model o zignorowanie promptu systemowego albo o odpowiedź wykraczającą poza jego zakres. Pokrywa się to z jailbreakingiem, choć cel jest inny. Jailbreaking zwykle celuje w wewnętrzny trening bezpieczeństwa modelu. Bezpośredni prompt injection celuje w to, co konkretnie twoja aplikacja kazała modelowi robić. Pośredni prompt injection to ten, który najczęściej zaskakuje zespoły. Złośliwy tekst dociera bez udziału osoby aktualnie prowadzącej rozmowę: nie napisała ona z niego ani słowa. Siedzi on zamiast tego w dokumencie, który podsumowuje twój asystent, na stronie internetowej, którą czyta twój agent badawczy, albo w zgłoszeniu, które przetwarza twoje narzędzie do klasyfikacji zgłoszeń. Model nie odróżni prawowitego akapitu od podrzuconej instrukcji, gdy oba są po prostu tekstem w kontekście. Pośredni prompt injection zasługuje na więcej uwagi, niż zwykle dostaje. Filtrowanie tego, co wpisuje użytkownik, nie wyłapie z niego niczego, bo użytkownik nigdy nie wpisał tego ataku. Osoba, która pyta, jest często równie zaskoczona jak ty.

Filtrowanie tego, co wpisuje użytkownik, nie powstrzymuje pośredniego ataku w żadnym stopniu. Instrukcja już siedzi w dokumencie, na stronie internetowej albo w zgłoszeniu, które twoja aplikacja i tak miała przeczytać. Zabezpieczenie ograniczone tylko do danych wejściowych od użytkownika całkowicie to przeoczy.

Dlaczego RAG i agenci zwiększają powierzchnię ataku

Chatbot odpowiadający według sztywnego scenariusza ma powierzchnię ataku ledwie wartą wzmianki. Dodaj wyszukiwanie kontekstowe (RAG) i to szybko się zmienia. Każdy dokument, który pipeline RAG dociąga do kontekstu, czyli artykuł pomocy, wgrany kontrakt, wynik wyszukiwania na żywo, to tekst, który model przeczyta i na podstawie którego może podjąć działanie. Poszerzasz źródła, z których korzysta, i tym samym poszerzasz miejsca, w których ktoś mógłby podrzucić instrukcję. Agenci pogarszają drugą połowę problemu: konsekwencje. Chatbot oszukany w nieautoryzowany temat marnuje jedną rozmowę. Agent oszukany w momencie, gdy trzyma narzędzie wysyłające e-maile, zapisujące dane w bazie albo wywołujące API płatności, może wykonać instrukcję, którą został oszukany, by uznać za prawowitą. Model robi dokładnie to, co mówi mu kontekst, a to właśnie kontekst został skompromitowany. Większość użytecznych funkcji LLM wymaga wyszukiwania kontekstowego, dostępu do narzędzi albo obu naraz. Prawdziwym zadaniem jest traktowanie każdego pobranego fragmentu i każdego wywołania narzędzia jako miejsca, do którego mógłby dotrzeć atakujący.

Jak zapobiegać prompt injection: zabezpieczenia, które faktycznie pomagają

Zapytaj pięciu dostawców, jak zapobiegać prompt injection, a dostaniesz pięć produktów do kupienia. Żaden z nich sam nie zamyka problemu. To, co sprawdza się w praktyce, to warstwowe układanie zabezpieczeń, tak by żadna pojedyncza porażka nie oddała atakującemu wyniku, o który mu chodzi. Zacznij od najsłabszej warstwy: hierarchii instrukcji, czyli takiego sformułowania promptu systemowego, by traktował określoną treść jako dane i ignorował instrukcje ukryte w jej wnętrzu. Pomaga to przeciwko przypadkowym próbom, a jednocześnie to warstwa, którą atakujący najłatwiej obchodzą metodą kolejnych prób. Traktuj to jako próg zwalniający. Nic więcej. Filtrowanie danych wejściowych i wyjściowych stoi o stopień wyżej: klasyfikator oznaczający treść, która wygląda jak instrukcja, albo dane wyjściowe, które wyglądają jak wyciek. Wyłapuje znane wzorce i zatrzymuje leniwe próby. Zdeterminowany atakujący przeformułuje, zakoduje albo podzieli ładunek, aż coś się prześlizgnie. Dwie warstwy, które faktycznie zmieniają wynik, gdy pierwsze dwie zawiodą: do kogo i do czego model ma dostęp oraz jak traktujesz to, co wychodzi na drugim końcu.

Warstwa zabezpieczeńCo powstrzymujeCzego nie wyłapuje
Utwardzanie danych wejściowych i promptuPrzypadkowe próby, znane sformułowaniaDobrze przygotowany albo pośredni atak
Dostęp do narzędzi i danych z minimalnymi uprawnieniamiSzkody po tym, jak atak się przedostanieSamą próbę ataku
Obsługa danych wyjściowych i weryfikacja przez człowiekaZmanipulowaną odpowiedź wywołującą realną szkodęNadużycia niskiego ryzyka, których nikt nie ograniczył
Monitorowanie i logowaniePowtarzające się próby, wykryte po fakciePierwszą udaną próbę

Dostęp do narzędzi i danych z minimalnymi uprawnieniami

Dostęp z minimalnymi uprawnieniami to zabezpieczenie, które wciąż się opłaca, nawet gdy każda inna warstwa zawiedzie. Daj modelowi i każdemu narzędziu, które wywołuje, tylko te uprawnienia i dane, których potrzebuje do zadania stojącego akurat przed nim. Agent supportu odpowiadający na pytania o rozliczenia nie potrzebuje dostępu do zapisu w bazie danych rozliczeniowych. Narzędzie do podsumowywania dokumentów nie potrzebuje narzędzia, które wysyła e-maile. Jeśli atak przemknie przez każdy filtr, promień rażenia zostaje mały, bo nic niebezpiecznego nie leży w zasięgu ręki. Ograniczaj zakres kluczy API i uprawnień narzędzi do pojedynczego zadania, a nie do całej aplikacji. Rozdziel dane uwierzytelniające, z których korzysta funkcja podsumowywania, od tych używanych przez funkcję rozliczeniową. Izoluj dane w podziale na tenantów, tak by dokumenty jednego klienta nigdy nie mogły odpowiedzieć na pytanie innego. To, jak wąski jest zasięg modelu, decyduje, czy atak kiedykolwiek cię coś kosztuje.

Twoja funkcja LLM właśnie stała się powierzchnią ataku

Gdy tylko model zaczyna czytać treści z zewnątrz albo trzymać narzędzie, prompt injection przestaje być hipotetycznym scenariuszem. Napisz nam, co zbudowałeś, co to czyta i czego wolno mu dotykać. Wskażemy, gdzie podrzucona instrukcja mogłaby wyrządzić szkodę i które zabezpieczenia najpierw zamykają tę lukę.

Zamów przegląd zabezpieczeń

Obsługa danych wyjściowych i weryfikacja przez człowieka

Wszystko, co model generuje na wyjściu, zasługuje na taką samą podejrzliwość, jaką potraktowałbyś tekst napisany przez nieznajomego w sieci. W pewnym sensie to może być dokładnie to: słowa nieznajomego, wyprane przez twój model. Wyrenderowanie takiego wyniku prosto na stronie internetowej bez odpowiedniego escapowania może zamienić udany atak w trwale zapisany skrypt, który uderza w każdego kolejnego odwiedzającego po tym pierwszym. Przekazanie go do zapytania bazodanowego albo polecenia powłoki zamienia problem językowy w problem wykonania kodu. Weryfikacja przez człowieka zamyka lukę, której nie zamknie żadna ilość filtrowania. Wszystko, co niesie realne konsekwencje: przelew pieniędzy, usunięcie rekordu, wysłanie e-maila do kogoś spoza twojej firmy, zmiana uprawnienia, powinno zatrzymać się i czekać na potwierdzenie człowieka, bez względu na to, jak pewnie brzmi model. Model, w który skutecznie wstrzyknięto instrukcję, brzmi dokładnie tak samo pewnie jak prawowity. Pewność siebie nigdy nie była sygnałem, któremu warto ufać.

Filtrowanie danych wyjściowych wyłapuje znane, złe wzorce w tym, co zwraca model. Nie wyłapie subtelnego wycieku sformułowanego w sposób, dla którego nikt jeszcze nie napisał reguły. Traktuj filtrowanie jak dziurawą sieć i za wszystkim, na czym naprawdę zależy, postaw granicę uprawnień.

Testowanie twoich zabezpieczeń

Testowanie zabezpieczeń przed prompt injection wygląda inaczej niż testowanie zwykłej funkcji. Wynik jest miarą odporności, bardziej gradientem niż polem do odhaczenia. Jedyną prawdziwą metodą jest red teaming własnej aplikacji: próbowanie ataków, które wypróbowałby ktoś z zewnątrz, zanim zrobi to ktoś inny. Pokryj obie strony. Wypróbuj bezpośrednie próby przez interfejs czatu, prosząc model o zignorowanie instrukcji albo ujawnienie promptu systemowego. Potem wypróbuj próby pośrednie: podrzuć instrukcję wewnątrz dokumentu, który twoja aplikacja realistycznie mogłaby wczytać, i sprawdź, czy model ją wykona. Mały, wrogo skonstruowany zestaw testowy wyłapie więcej niż kiedykolwiek wyłapie dużo większy zestaw pytań ze zwykłego użycia. Uruchamiaj to przed startem, a potem za każdym razem, gdy zmienia się prompt systemowy albo źródło danych: z tą samą dyscypliną, jaką nasz przewodnik po metrykach ewaluacji LLM opisuje przy testach regresyjnych. Osoba, która napisała zabezpieczenie, zwykle jest najgorszą osobą do jego testowania. Zaangażuj kolegę z zespołu, żeby spędził dwadzieścia minut, próbując je złamać.

Bazowy poziom bezpieczeństwa na etapie MVP

Jeśli szybko wdrażasz produkt, nie potrzebujesz pierwszego dnia zabezpieczeń o głębokości korporacyjnej. Realistyczny bazowy poziom na etapie MVP obejmuje cztery rzeczy:

  • Ogranicz każde narzędzie i każde połączenie z danymi do najwęższych potrzebnych uprawnień
  • Domyślnie traktuj całą pobraną treść i cały wynik modelu jako niezaufane
  • Wymagaj potwierdzenia człowieka przed wykonaniem czegokolwiek, co niesie realne konsekwencje
  • Loguj wystarczająco dużo aktywności, by dało się zauważyć dziwny wzorzec

Zaplanuj na to budżet od samego początku. Praca nad zabezpieczeniami jest częścią samej funkcji. Pominięcie jej odezwie się później zgłoszeniem do supportu albo czymś gorszym. Nasz przewodnik po kosztach budowy aplikacji AI wycenia, ile to dokłada do budowy. Zabezpieczenie przed prompt injection to jeden element szerszego obrazu bezpieczeństwa. Resztę pokrywa nasz przewodnik po bezpieczeństwie i skalowalności w rozwoju MVP. Żadne z tych ustawień nie czyni funkcji LLM odpornej na zdeterminowanego atakującego. Warstwowy poziom bazowy, do którego wracasz w miarę rozwoju funkcji, sprawia, że realistyczny atakujący musi pracować ciężej, niż wart jest efekt. Jeśli planujesz zabezpieczenia dla funkcji dotykającej prawdziwych danych użytkowników, porozmawiaj z naszym zespołem integracji AI, a dobierzemy zabezpieczenia dopasowane do skali.

Tags

Często zadawane pytania

Znajdź odpowiedzi na często zadawane pytania dotyczące tego tematu.