Dzisiaj mamy dużo kodu… jak na ten przegląd wręcz zadziwiająco dużo. Ale też akurat jest go całkiem sporo ciekawego do pokazania, zwłaszcza w kontekście ostatniej premiery Kotlina i dużej podatności Springa. Ale i tak gwiazdą całości jest nowy Hibernate 🥶.
1. W końcu wyszedł Kotlin 1.6.20
W ostatnich paru tygodniach w świecie Kotlina było naprawdę cicho – ale tak cicho cicho, że newsletter Kotlin Weekly zaczął grzebać łychą pod dnie gara, i to raczej wiosłując po mocno przypalone resztki. Sami już kilka edycji temu uspokoiliśmy, że inwazja Rosji na Ukrainę nie powinna być egzystencjalnym problemem dla języka mimo jego korzeni, jednak oczekiwania na kolejną edycję nieco się przeciągały. Oto jednak mamy wydanie 1.6.20, które zgodnie z Kotlinowym cyklem releasowym jest wydaniem przygotowującym nas powoli do wersji 1.7. Co zatem ciekawego przyniesie i czy warto było czekać?
Dużą zmianą, przyniesioną przez Kotlina 1.6.20 to tak zwane Context Receivers. Już w tej chwili w ramach Kotlina dość popularnym konceptem są funkcje rozszerzające (extension functions). Pozwalają one dodać funkcję do hmmm… powiedzieć obiektów byłoby sporym przekłamaniem. Jeśli weźmiemy sobie za przykład:
fun List<Int>.sum():
w tego typu wywołaniu odbiorcą (receiverem) będzie List<Int> – czyli kontener (List) razem z parametrem (Int).
Prosto, prawda? To twórcy Kotlina postanowili to nieco utrudnić (ale nie martwcie się, wszystko dla Waszego dobra 😉. Otóż, od tej pory będzie można zdefiniować nie tylko odbiorcę, ale również bardzo precyzyjnie zawęzić kontekst, w którym może on pracować. Popatrzcie na poniższy przykład:
context(Comparator<A>)
fun <A> List<A>.sort(): List<A> = sortedWith(this@Comparator)
O ile w powyższym przypadku .sum() mogło być użyte w całym zdefiniowanym scope (zwykle konkretnym pliku lub module), o tyle powyższe.sort zadziała tylko w kontekście konkretnego komparatora.
with(Comparator.naturalOrder<Int>()) {
listOf(3, 5, 1).sort()
}
Oprócz tego, aby zapewnić lepszą interoperacyjność podczas rozszerzania ogólnych klas i interfejsów Java, Kotlin 1.6.20 umożliwia oznaczenie generyków jako nie dopuszczającego wartości null. Wprowadzono również obsługę struktury hierarchicznej dla projektów wieloplatformowych – Kotlin Multiplatform otrzymał też łatwiejszą możliwość dzielenia się kodem między poszczególnymi platformami.
Sporo zmian dotknęło też kompilator. Wprowadzono równoległą kompilację plików (można ją uruchomić eksperymentalną flagą -Xbackend-threads) oraz inkrementalną kompilację dla Kotlin/JS. Wykorzystuje on zbuforowane wyniki kompilacji dla niezmienionych plików źródłowych podczas kolejnych kompilacji, dzięki czemu ich ukończenie przebiega szybciej, zwłaszcza przy niewielkich zmianach.
Trochę tego jest jak widzicie, aczkolwiek większość zmian to jednak pod maską. Ciekawe, co poza stabilnymi Context Receivers zobaczymy w kolejnym “dużym” wydaniu Kotlina.
Źródła
Zainstaluj teraz i czytaj tylko dobre teksty!
2. Czy SpringShell to nowy Log4Shell?
Podejrzewam, że mało kto miał przyjemność zapomnieć o Log4Shellu, podatności która wręcz przeorała javowy ekosystem i pozwoliła zarobić wielu pracownikom działów IT na wypasione święta, przynajmniej w firmach, które wypłacają nadgodziny – bo tych było w tym okresie masakrycznie dużo. Pamiętam też pociechę, którą powtarzali sobie dojechani robotą programiści – “Dobrze, że Spring nie jest podatny… to by dopiero było”. Dlatego gdy sieć obiegła informacja o nowej wykrytej podatności w ramach tego właśnie frameworka, wszystkich oblał blady strach i informacja zaczęła obiegać firmowe (i nie tylko) Slacki w tempie błyskawicy.
Dodatkowo, cała podatność wydaje się mieć świetnych speców od Public Relations, ponieważ z miejsca została ogłoszona jako SpringShell, więc pod nazwą sugerującą groźne konotacje (a dodatkowo będąc nazwą taką samą jak jeden z modułów Spring Boot, więc jej wyszukanie w Google wcale nie jest takie oczywiste).
Czym tak naprawdę jest Spring Shell? Otóż okazało się, że w JDK9+ (i tak, jeśli używacie ciągle ósemki, możecie przestać czytać), poprzez mechanizm DataBinding (czyli mapowania parametrów URL na istniejące klasy), możliwe jest wstrzyknięcie wewnętrznych parametrów danej klasy.
Poniższy kod pochodzi z oficjalnej dokumentacji Springa i…. jest podatny na atak:
@PostMapping("/greeting")
public String greetingSubmit(@ModelAttribute Greeting greeting, Model model) {
model.addAttribute("greeting", greeting);
return "result";
}
public class Greeting {
private long id;
private String content;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
Oczywiście, są takie parametry, które raczej nie chcielibyśmy mieć możliwości nadpisać, ze względów bezpieczeństwa. Spring w swoim kodzie bezpośrednio broni się przed próbą takiego działania:
if (Class.class == beanClass && ("classLoader".equals(pd.getName()) || "protectionDomain".equals(pd.getName()))) {
// Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those
continue;
}
Okazało się, że wraz z JDK 9 pojawiła się nowa metoda Class.getModule(), a twórcy Springa… zapomnieli ją również zabezpieczyć jako kolejny warunek w powyższym “ifie”. Poprzez tą metodę, atakujący może nadpisać pola w ramach Class Loadera. Na ten moment, udało się przygotować z użyciem powyższego mechanizmu skuteczny atak Apache Tomcat ze Springiem deployowanym jako *.war – możliwe jednak, że w przyszłości wektor ataku stanie się szerszy. Jeśli chcecie więcej detali, całość została świetnie opisana przez jFrog.
Najlepszym sposobem na naprawienie SpringShell jest aktualizacja Spring Framework do wersji 5.2.20 lub 5.3.18. Użytkownicy Spring Boot powinni zaś przeskoczyć do wersji 2.6.6.
Żeby podtrzymać atmosferę grozy, chciałbym się tutaj podzielić jakimś mrożącą krew oceną związanego z podatnością ryzyka, ale w obecnej chwili CVE-2022-22965, bo taką sygnaturę dostała, czeka jeszcze ona na dokładniejszą analizę. Problem został już załatany, ale ciekawe, czy sprawa dostanie drugie życie tak jak było to w wypadku Log4Shell.
Źródła
- SpringShell (Spring4Shell) Zero-Day Vulnerability CVE-2022-22965 : All You Need To Know
- NVD – CVE-2022-22965
- https://github.com/spring-projects/spring-framework/blob/b595dc1dfad9db534ca7b9e8f46bb9926b88ab5a/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java#L290
Zainstaluj teraz i czytaj tylko dobre teksty!
3. Hibernate 6.0 – pierwsze duże wydanie od dekady
Oj, wysypało nam ostatnio nowych “dużych” wydań od projektów, które nie były aktualizowane od dobrych parę lat. W zeszły poniedziałek informowaliśmy o nowym Clojure, w czwartek o React 18, a dzisiaj mamy Hibernate 6.0 – edycję, która jest pierwszym “majorem” Hibernate od roku 2011 😉. Nie oznacza to oczywiście, że rozwój biblioteki stał w miejscu – każda z regularnie wydawanych minorów 5.x przynosiła nowości. Ostatnimi czasy jednak nie tylko więcej mówiło się o pobocznych projektach, takich jak Hibernate Reactive, ale i sama biblioteka nie przynosił pozytywnych (a w najlepszym wypadku – neutralne) skojarzenia. Czy “szóstka” ma szansę pomóc odzyskać Hibernate zalśnić na nowo?
Nowy Hibernate to przede wszystkim nowe adnotacje, które porzuciły swoje XMLowe korzenie i doczekały się sporej ilości zmian min. lepsze type-safety. Dużym krokiem do przodu jest też Semantic Query Model (SQM) – nowy parser zapytań o encje, który obsługuje zarówno JPQL, jak i Criteria API. Nowy parser będzie znacznie bardziej elastyczny, dzięki czemu zapewniamy lepszą translację zapytań o encje w języku SQL. Dodatkowo, pojawiła się poprawa wydajności poprzez zmianę z odczytu kolumn po nazwie na odczyt według pozycji w ramach ResultSetu oraz aktualizacja używanego przez Hibernate parsera z ANTLR 2 na 4.
Bardzo dużą zmianą jest też migracja Hibernate na Jakartę EE i porzucenie starych API związanych z Java EE. To właśnie min. z tym wiąże się podbicie dużej wersji aplikacji – z wiadomych względów, pojawia się potrzeba migracji z przestrzeni nazw javax.persistence do jakarta.persistence. Na szczęście powstał do tego specjalny automatyczny Transformer.
A skoro już o tym mówimy, nie można nie wspomnieć o nowej wersji Jakarty Persistence. Standard będący kontynuacją znanego pewnie większości JPA (Java Persistence API) ukazał się w wersji 3.1, która to stanie się częścią nadchodzącej Jakarty EE 10. Ta przynosi porządne wsparcie dla UUID (java.util.UUID wreszcie jest traktowane jako typ podstawowy), rozwinięcie Query Language and Criteria API. Pojawiły się też nowe funkcje numeryczne (jak FLOOR czy ROUND), lepsze wsparcie dla LocalDate oraz wyciąganie konkretnych fragmentów daty za pomoc EXTRACT z SQL.