Jak pobrać URL lub webhook podany przez użytkownika bez ryzyka SSRF?
zespół heygrc
Zwaliduj cel przed jego pobraniem: wymagaj protokołu https, rozwiń nazwę hosta i odrzuć adresy prywatne, wewnętrzne oraz link-local (w tym punkty końcowe metadanych chmury). Preferuj listę dozwolonych, jeśli miejsca docelowe są znane, i nie podążaj ślepo za przekierowaniami. Server-side request forgery to problem walidacji wejścia (NIST 800-53 SI-10), a sprawdzenie powinno znaleźć się w kodzie, który wykonuje żądanie.
Zwaliduj cel
Zezwól jedynie na schematy, których zamierzasz używać (zazwyczaj https), i odrzuć adresy z zakresów prywatnych, loopback, link-local oraz metadanych. Zwaliduj rozdzielony adres w momencie nawiązywania połączenia, a nie tylko na podstawie URL na początku, ponieważ DNS może rozdzielić inaczej między wstępną weryfikacją a rzeczywistym żądaniem (DNS rebinding).
Preferuj listę dozwolonych
Jeśli zbiór miejsc docelowych jest znany (stała lista punktów końcowych partnerów), użyj listy dozwolonych zamiast akceptować dowolne URL. Im węższe wejście akceptujesz, tym mniej jest miejsc na błędy.
Nie podążaj ślepo za przekierowaniami
Przekierowanie może wysłać zwalidowany publiczny URL do wewnętrznego adresu na następnym hopie. Ponownie zwaliduj przy każdym przekierowaniu lub wyłącz podążanie za przekierowaniami dla celów podanych przez użytkownika.
async function send(url, payload) {- return fetch(url, { method: 'POST', body: payload })+ // safeFetch waliduje ROZDZIELONY adres w momencie nawiązywania połączenia+ return safeFetch(url, { method: 'POST', body: payload, allowRedirects: false })}Walidacja rozdzielonego adresu w momencie nawiązywania połączenia, a nie tylko na podstawie URL na początku (co może zostać pokonane przez DNS rebinding), uniemożliwia dotarcie do wewnętrznych usług przez celowo przygotowany adres docelowy.