Kontrol Sesi dengan Keamanan Musim Semi

1. Ikhtisar

Pada artikel ini, kami akan mengilustrasikan bagaimana Keamanan Musim Semi memungkinkan kami mengontrol Sesi HTTP kami .

Kontrol ini berkisar dari waktu tunggu sesi hingga mengaktifkan sesi bersamaan dan konfigurasi keamanan lanjutan lainnya.

2. Kapan Sesi Dibuat?

Kami dapat mengontrol dengan tepat kapan sesi kami dibuat dan bagaimana Keamanan Musim Semi akan berinteraksi dengannya:

  • selalu - sesi akan selalu dibuat jika belum ada
  • ifRequired - sesi hanya akan dibuat jika diperlukan ( default )
  • never - framework tidak akan pernah membuat sesi itu sendiri tetapi akan menggunakannya jika sudah ada
  • stateless - tidak ada sesi yang akan dibuat atau digunakan oleh Keamanan Musim Semi
...

Konfigurasi Java:

@Override protected void configure(HttpSecurity http) throws Exception { http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) }

Sangat penting untuk dipahami bahwa konfigurasi ini hanya mengontrol apa yang dilakukan Spring Security - bukan seluruh aplikasi. Keamanan Musim Semi tidak dapat membuat sesi jika kami menginstruksikan untuk tidak melakukannya, tetapi aplikasi kami mungkin!

Secara default, Spring Security akan membuat sesi saat dibutuhkan - ini adalah " ifRequired ".

Untuk aplikasi yang lebih stateless , opsi " never " akan memastikan bahwa Spring Security sendiri tidak akan membuat sesi apa pun; namun, jika aplikasi membuatnya, Spring Security akan memanfaatkannya.

Terakhir, opsi pembuatan sesi yang paling ketat - " stateless " - adalah jaminan bahwa aplikasi tidak akan membuat sesi apa pun sama sekali .

Ini diperkenalkan pada Spring 3.1 dan secara efektif akan melewati bagian rantai filter Keamanan Musim Semi - terutama bagian terkait sesi seperti HttpSessionSecurityContextRepository , SessionManagementFilter , RequestCacheFilter .

Mekanisme kontrol yang lebih ketat ini memiliki implikasi langsung bahwa cookie tidak digunakan sehingga setiap permintaan perlu diautentikasi ulang . Arsitektur stateless ini berfungsi baik dengan REST API dan batasan Statelessness-nya. Mereka juga bekerja dengan baik dengan mekanisme otentikasi seperti Otentikasi Dasar dan Intisari.

3. Di Balik Terpal

Sebelum menjalankan proses Otentikasi, Keamanan Musim Semi akan menjalankan filter yang bertanggung jawab dengan menyimpan Konteks Keamanan antar permintaan - SecurityContextPersistenceFilter . Konteks akan disimpan sesuai dengan strategi - HttpSessionSecurityContextRepository secara default - yang menggunakan Sesi HTTP sebagai penyimpanan.

Untuk atribut ketat create-session = "stateless" , strategi ini akan diganti dengan yang lain - NullSecurityContextRepository - dan tidak ada sesi yang akan dibuat atau digunakan untuk mempertahankan konteks.

4. Kontrol Sesi Bersamaan

Ketika pengguna yang sudah diautentikasi mencoba untuk mengautentikasi lagi , aplikasi dapat menangani kejadian itu dengan salah satu dari beberapa cara. Ini dapat membuat sesi aktif pengguna menjadi tidak valid dan mengautentikasi pengguna lagi dengan sesi baru, atau mengizinkan kedua sesi tersebut ada secara bersamaan.

Langkah pertama dalam mengaktifkan dukungan kontrol-sesi serentak adalah menambahkan listener berikut di web.xml :

  org.springframework.security.web.session.HttpSessionEventPublisher  

Atau definisikan sebagai Bean - sebagai berikut:

@Bean public HttpSessionEventPublisher httpSessionEventPublisher() { return new HttpSessionEventPublisher(); }

Ini penting untuk memastikan bahwa registri sesi Keamanan Musim Semi diberi tahu saat sesi dihancurkan .

Untuk mengaktifkan skenario yang memungkinkan beberapa sesi bersamaan untuk pengguna yang sama, elemen harus digunakan dalam konfigurasi XML:

Atau, melalui konfigurasi Java:

@Override protected void configure(HttpSecurity http) throws Exception { http.sessionManagement().maximumSessions(2) }

5. Batas Waktu Sesi

5.1. Menangani Timeout Sesi

Setelah sesi habis waktunya, jika pengguna mengirim permintaan dengan id sesi yang telah habis masa berlakunya , mereka akan dialihkan ke URL yang dapat dikonfigurasi melalui namespace:

Demikian pula, jika pengguna mengirim permintaan dengan id sesi yang tidak kedaluwarsa, tetapi sepenuhnya tidak valid , mereka juga akan dialihkan ke URL yang dapat dikonfigurasi:

 ... 

Konfigurasi Java yang sesuai:

http.sessionManagement() .expiredUrl("/sessionExpired.html") .invalidSessionUrl("/invalidSession.html");

5.2. Konfigurasikan Timeout Sesi dengan Spring Boot

Kami dapat dengan mudah mengkonfigurasi nilai batas waktu sesi dari server tertanam menggunakan properti:

server.servlet.session.timeout=15m

Jika kita tidak menentukan unit durasi, Spring akan menganggapnya detik.

Singkatnya, dengan konfigurasi ini, setelah 15 menit tidak ada aktivitas, sesi akan berakhir. Sesi setelah jangka waktu ini dianggap tidak valid.

Jika kami mengonfigurasi proyek kami untuk menggunakan Tomcat, kami harus ingat bahwa itu hanya mendukung presisi menit untuk batas waktu sesi, dengan minimal satu menit. Ini berarti bahwa jika kita menetapkan nilai batas waktu 170s misalnya, akan menghasilkan batas waktu 2 menit.

Terakhir, penting untuk disebutkan bahwa meskipun Sesi Musim Semi mendukung properti serupa untuk tujuan ini ( spring.session.timeout ), jika itu tidak ditentukan maka konfigurasi otomatis akan mengembalikan ke nilai properti yang pertama kali kita sebutkan.

6. Mencegah Penggunaan Parameter URL untuk Pelacakan Sesi

Mengekspos informasi sesi di URL merupakan risiko keamanan yang meningkat (dari tempat 7 pada tahun 2007 menjadi tempat 2 pada tahun 2013 di Daftar 10 Teratas OWASP).

Dimulai dengan Spring 3.0, logika penulisan ulang URL yang akan menambahkan jsessionid ke URL sekarang dapat dinonaktifkan dengan menyetel disable-url-rewriting = "true" di namespace.

Atau, dimulai dengan Servlet 3.0, mekanisme pelacakan sesi juga dapat dikonfigurasi di web.xml:

 COOKIE 

Dan secara terprogram:

servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE));

Ini memilih tempat untuk menyimpan JSESSIONID - di cookie atau di parameter URL.

7. Perlindungan Fiksasi Sesi Dengan Keamanan Pegas

Kerangka kerja ini menawarkan perlindungan terhadap serangan Fiksasi Sesi tipikal dengan mengonfigurasi apa yang terjadi pada sesi yang ada saat pengguna mencoba untuk mengautentikasi lagi:

 ...

Konfigurasi Java yang sesuai:

http.sessionManagement() .sessionFixation().migrateSession()

Secara default, Spring Security mengaktifkan perlindungan ini (" migrateSession ") - saat autentikasi, Sesi HTTP baru dibuat, yang lama tidak valid dan atribut dari sesi lama disalin.

Jika ini bukan perilaku yang diinginkan, tersedia dua opsi lain:

  • ketika " tidak ada " disetel, sesi asli tidak akan dibatalkan
  • when “newSession” is set, a clean session will be created without any of the attributes from the old session being copied over

8. Secure Session Cookie

Next, we'll discuss how to secure our session cookie.

We can use the httpOnly and secure flags to secure our session cookie:

  • httpOnly: if true then browser script won't be able to access the cookie
  • secure: if true then the cookie will be sent only over HTTPS connection

We can set those flags for our session cookie in the web.xml:

 1  true true  

This configuration option is available since Java servlet 3. By default, http-only is true and secure is false.

Let's also have a look at the corresponding Java configuration:

public class MainWebAppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext sc) throws ServletException { // ... sc.getSessionCookieConfig().setHttpOnly(true); sc.getSessionCookieConfig().setSecure(true); } }

If we're using Spring Boot, we can set these flags in our application.properties:

server.servlet.session.cookie.http-only=true server.servlet.session.cookie.secure=true

Finally, we can also achieve this manually by using a Filter:

public class SessionFilter implements Filter { @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; Cookie[] allCookies = req.getCookies(); if (allCookies != null) { Cookie session = Arrays.stream(allCookies).filter(x -> x.getName().equals("JSESSIONID")) .findFirst().orElse(null); if (session != null) { session.setHttpOnly(true); session.setSecure(true); res.addCookie(session); } } chain.doFilter(req, res); } }

9. Working With the Session

9.1. Session Scoped Beans

A bean can be defined with session scope simply by using the @Scope annotation on beans declared in the web-Context:

@Component @Scope("session") public class Foo { .. }

Or with XML:

Then, the bean can simply be injected into another bean:

@Autowired private Foo theFoo;

And Spring will bind the new bean to the lifecycle of the HTTP Session.

9.2. Injecting the Raw Session into a Controller

The raw HTTP Session can also be injected directly into a Controller method:

@RequestMapping(..) public void fooMethod(HttpSession session) { session.setAttribute(Constants.FOO, new Foo()); //... Foo foo = (Foo) session.getAttribute(Constants.FOO); }

9.3. Obtaining the Raw Session

Sesi HTTP saat ini juga dapat diperoleh secara terprogram melalui API Servlet mentah :

ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpSession session= attr.getRequest().getSession(true); // true == allow create

10. Kesimpulan

Pada artikel ini, kita membahas pengelolaan Sesi dengan Keamanan Musim Semi. Juga, Referensi Musim Semi berisi FAQ yang sangat bagus tentang Manajemen Sesi.

Seperti biasa, kode yang disajikan dalam artikel ini tersedia di Github. Ini adalah proyek berbasis Maven, jadi semestinya mudah untuk mengimpor dan menjalankan apa adanya.