O 123% więcej zgłoszonych CVE dziennie w 2026 niż przed rokiem.

Łańcuch dostaw

Czym jest dependency confusion?

Dependency confusion to atak, w którym build instaluje publiczny pakiet napastnika zamiast Państwa prywatnego pakietu o tej samej nazwie. Nikt nie popełnia literówki. Napastnikowi wystarczy poznać nazwę pakietu wewnętrznego i opublikować ją w publicznym rejestrze z wysokim numerem wersji, a resztę załatwia źle skonfigurowany build.

Zaktualizowano

Jak działa atak dependency confusion

  1. Znalezienie nazwy wewnętrznej. Nazwy prywatnych pakietów wyciekają przez publiczny kod, bundle JavaScript, komunikaty o błędach i manifesty pozostawione w repozytoriach.
  2. Publikacja tej samej nazwy publicznie. Napastnik rejestruje ją w npm, PyPI lub innym publicznym rejestrze z bardzo wysokim numerem wersji.
  3. Oczekiwanie na build. Menedżer pakietów skonfigurowany tak, by sprawdzać rejestr wewnętrzny i publiczny, znajduje dwóch kandydatów i wybiera wyższą wersję.
  4. Uruchomienie wewnątrz firmy. Skrypt instalacyjny pakietu uruchamia się na komputerze programisty lub runnerze CI i ma dostęp do wszystkiego, co tam jest.

Badanie, które nadało nazwę

W lutym 2021 r. badacz bezpieczeństwa Alex Birsan opublikował tę technikę. Wcześniej użył jej, aby uruchomić kod wewnątrz ponad 35 organizacji, w tym Apple, Microsoft i PayPal, w ramach programów bug bounty lub za zgodą. Zadziałała we wszystkich trzech językach, które testował, a napastnicy zaczęli ją kopiować w ciągu kilku dni od publikacji.

Dlaczego tak się dzieje

Główną przyczyną jest menedżer pakietów, który traktuje kilka rejestrów jako równorzędne. Klasycznym przykładem jest Python: --extra-index-url w pip dodaje drugie źródło obok PyPI, a pip może zainstalować pakiet publiczny, jeśli znajdzie taki o tej samej nazwie.

# Unsafe for private packages: both indexes are candidates
pip install --extra-index-url https://pypi.internal.example/simple my-internal-lib

# Safer: one index you control, which proxies public packages
pip install --index-url https://pypi.internal.example/simple my-internal-lib

npm ma ten sam problem z wewnętrznymi nazwami bez zakresu, a zakres powiązany z Państwa rejestrem go eliminuje.

# .npmrc: everything under @acme comes only from your registry
@acme:registry=https://npm.internal.example/

Jak zapobiegać dependency confusion

  • Używać jednego źródła prawdy. Kierować buildy na jeden wewnętrzny rejestr, który pośredniczy w dostępie do pakietów publicznych, i skonfigurować go tak, aby nazwy wewnętrzne nigdy nie były rozwiązywane publicznie.
  • Używać zakresów lub przestrzeni nazw. Posiadać zakres taki jak @acme w rejestrze publicznym i mapować go na swój rejestr prywatny.
  • Zarezerwować swoje nazwy. Zarejestrować nazwy pakietów wewnętrznych w rejestrach publicznych, aby nikt inny nie mógł tego zrobić.
  • Przypinać i weryfikować. Commitować lockfile i używać sprawdzania hashy, takiego jak --require-hashes w pip, aby instalacja innego pakietu kończyła się błędem. Zob. co lockfile robi, a czego nie.
  • Ograniczać, dokąd mogą łączyć się buildy. Jeśli build ma dostęp tylko do Państwa rejestru, w ogóle nie może pobrać pakietu napastnika. Zob. politykę ruchu wychodzącego w GitHub Actions.
  • Sprawdzać, co wycieka. Przeszukiwać publiczny kod i bundle klienckie pod kątem nazw pakietów wewnętrznych.

Dependency confusion a typosquatting

Typosquatting polega na tym, że człowiek myli się przy wpisywaniu nazwy pakietu publicznego. Dependency confusion wykorzystuje dokładną nazwę pakietu prywatnego i opiera się na konfiguracji buildu. Oba prowadzą do tego samego: kodu napastnika działającego w Państwa buildzie. Ich miejsce wśród innych ataków opisuje strona czym jest atak na łańcuch dostaw.

Jak sprawdzić, czy Państwa to dotknęło

Należy szukać nazw pakietów wewnętrznych rozwiązanych z rejestru publicznego lub wersji, które nie istnieją w rejestrze wewnętrznym. Trudno to zrobić na podstawie samego lockfile, ponieważ pytanie brzmi, skąd pakiet faktycznie pochodził podczas buildu.

Jak pomaga CRACI

CRACI działa w miejscu, w którym pakiet jest pobierany. Jako Państwa runner GitHub Actions egzekwuje politykę ruchu wychodzącego z typowanymi źródłami dla rejestrów, więc build można ograniczyć do rejestrów, na które Państwo zezwalają. Rejestruje też w SBOM każdy pakiet pobrany przez każde zadanie, dzięki czemu widzą Państwo, co trafiło do buildu. CRACI nie wykrywa, że pakiet jest złośliwy, dlatego pierwszą linią obrony powinna pozostać konfiguracja rejestru. Zob. dobre praktyki bezpieczeństwa łańcucha dostaw oprogramowania.

Dependency confusion: najczęściej zadawane pytania

Czym jest atak dependency confusion?

To atak, w którym przez pomyłkę instalowany jest pakiet publiczny o tej samej nazwie co prywatny, ponieważ menedżer pakietów sprawdza oba rejestry i wybiera wyższą wersję.

Czym dependency confusion różni się od typosquattingu?

Typosquatting polega na tym, że ktoś myli się przy wpisywaniu nazwy pakietu publicznego. Dependency confusion wykorzystuje dokładną nazwę pakietu prywatnego i opiera się na konfiguracji buildu, która sprawdza rejestry publiczne.

Jak zapobiegać dependency confusion?

Należy używać jednego rejestru wewnętrznego, nazw pakietów z zakresem, lockfile ze sprawdzaniem hashy i reguł ograniczających, do których rejestrów buildy mają dostęp. Pomaga też publiczne zarezerwowanie nazw wewnętrznych.

Czy --extra-index-url jest bezpieczne?

Nie dla pakietów prywatnych. Oba indeksy stają się kandydatami, więc może zostać zainstalowany pakiet publiczny o tej samej nazwie. Należy użyć --index-url z jednym indeksem pod własną kontrolą.

Kto odkrył dependency confusion?

Badacz bezpieczeństwa Alex Birsan opublikował tę technikę w lutym 2021 r., po użyciu jej wobec ponad 35 organizacji w ramach programów bug bounty lub za zgodą.

Ograniczyć, skąd buildy mogą pobierać

Proszę dopuścić tylko rejestry potrzebne zadaniu GitHub Actions i zobaczyć każdy pakiet, który pobrało.

Umów demo