Kawal Sesi dengan Keselamatan Musim Semi

1. Gambaran keseluruhan

Dalam artikel ini, kami akan menggambarkan bagaimana Spring Security membolehkan kami mengawal Sesi HTTP kami .

Kawalan ini berkisar dari tamat waktu sesi hingga membolehkan sesi bersamaan dan konfigurasi keselamatan lanjutan yang lain.

2. Bilakah Sesi Dibuat?

Kami dapat mengawal dengan tepat bila sesi kami dibuat dan bagaimana Spring Security akan berinteraksi dengannya:

  • selalu - sesi akan selalu dibuat sekiranya tidak ada
  • ifRequired - sesi akan dibuat hanya jika diperlukan ( lalai )
  • tidak pernah - kerangka kerja tidak akan membuat sesi itu sendiri tetapi ia akan menggunakannya jika sudah ada
  • tanpa status - tidak ada sesi yang akan dibuat atau digunakan oleh Spring Security
...

Konfigurasi Java:

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

Sangat penting untuk memahami bahawa konfigurasi ini hanya mengawal apa yang dilakukan oleh Spring Security - bukan keseluruhan aplikasi. Spring Security mungkin tidak membuat sesi jika kami mengarahkannya tidak, tetapi aplikasi kami mungkin!

Secara lalai, Spring Security akan membuat sesi apabila memerlukannya - ini adalah " ifRequired ".

Untuk aplikasi yang lebih stateless , pilihan " tidak pernah " akan memastikan bahawa Spring Security sendiri tidak akan membuat sesi; namun, jika aplikasinya dibuat, maka Spring Security akan menggunakannya.

Akhirnya, pilihan pembuatan sesi yang paling ketat - " tanpa status " - adalah jaminan bahawa aplikasi tidak akan membuat sesi sama sekali .

Ini diperkenalkan pada Spring 3.1 dan secara berkesan akan melangkau bahagian rantai penapis Spring Security - terutamanya bahagian yang berkaitan dengan sesi seperti HttpSessionSecurityContextRepository , SessionManagementFilter , RequestCacheFilter .

Mekanisme kawalan yang lebih ketat ini mempunyai implikasi langsung bahawa kuki tidak digunakan dan oleh itu setiap permintaan perlu disahkan semula . Senibina tanpa status ini bermain dengan baik dengan API REST dan kekangan Statelessness mereka. Mereka juga berfungsi dengan baik dengan mekanisme pengesahan seperti Pengesahan Asas dan Digest.

3. Di bawah Tudung

Sebelum menjalankan proses Pengesahan, Spring Security akan menjalankan penapis yang bertanggungjawab dengan menyimpan Konteks Keselamatan antara permintaan - SecurityContextPersistenceFilter . Konteks akan disimpan mengikut strategi - HttpSessionSecurityContextRepository secara lalai - yang menggunakan Sesi HTTP sebagai penyimpanan.

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

4. Kawalan Sesi Serentak

Apabila pengguna yang telah disahkan disahkan cuba mengesahkannya lagi , aplikasi dapat menangani peristiwa itu dengan beberapa cara. Ini boleh membatalkan sesi aktif pengguna dan mengesahkan pengguna sekali lagi dengan sesi baru, atau membiarkan kedua-dua sesi itu wujud serentak.

Langkah pertama untuk mengaktifkan sokongan kawalan sesi bersamaan adalah dengan menambahkan pendengar berikut di web.xml :

  org.springframework.security.web.session.HttpSessionEventPublisher  

Atau tentukannya sebagai Kacang - seperti berikut:

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

Ini mustahak untuk memastikan bahawa pendaftaran sesi Spring Security diberitahu ketika sesi itu dimusnahkan .

Untuk mengaktifkan senario yang membolehkan beberapa sesi serentak 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. Waktu Tamat Sesi

5.1. Mengendalikan Waktu Tamat Sesi

Setelah sesi tamat, jika pengguna mengirimkan permintaan dengan id sesi yang telah habis masa berlakunya , mereka akan diarahkan ke URL yang dapat dikonfigurasi melalui ruang nama:

Begitu juga, jika pengguna mengirim permintaan dengan id sesi yang tidak luput, tetapi tidak sah , mereka juga akan diarahkan ke URL yang dapat dikonfigurasi:

 ... 

Konfigurasi Java yang sesuai:

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

5.2. Konfigurasikan Timeout Session dengan Spring Boot

Kita dapat dengan mudah mengkonfigurasi nilai tamat masa Sesi pelayan terbenam menggunakan sifat:

server.servlet.session.timeout=15m

Sekiranya kita tidak menentukan unit jangka masa, Spring akan menganggap detik.

Ringkasnya, dengan konfigurasi ini, setelah 15 minit tidak aktif, sesi akan tamat. Sesi selepas jangka masa ini dianggap tidak sah.

Sekiranya kita mengkonfigurasi projek kita untuk menggunakan Tomcat, kita harus ingat bahawa ia hanya menyokong ketepatan minit untuk tamat sesi, dengan minimum satu minit. Ini bermaksud bahawa jika kita menentukan nilai timeout 170s misalnya, itu akan menghasilkan timeout 2 minit.

Akhirnya, penting untuk disebutkan bahawa walaupun Spring Session menyokong harta yang serupa untuk tujuan ini ( spring.session.timeout ), jika itu tidak ditentukan, maka konfigurasi automatik akan dikembalikan kepada nilai harta tanah yang pertama kali kita nyatakan.

6. Cegah Menggunakan Parameter URL untuk Penjejakan Sesi

Mendedahkan maklumat sesi di URL adalah risiko keselamatan yang semakin meningkat (dari tempat ke-7 pada tahun 2007 ke tempat ke-2 pada tahun 2013 dalam Senarai 10 Teratas OWASP).

Bermula dengan Spring 3.0, logik penulisan semula URL yang akan menambahkan jsessionid ke URL kini boleh dilumpuhkan dengan menetapkan disable-url-rewriting = "true" di ruang nama.

Sebagai alternatif, bermula dengan Servlet 3.0, mekanisme penjejakan sesi juga dapat dikonfigurasi di web.xml:

 COOKIE 

Dan secara terprogram:

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

Ini memilih tempat menyimpan JSESSIONID - dalam kuki atau parameter URL.

7. Perlindungan Fiksasi Sesi Dengan Keselamatan Musim Semi

Rangka kerja ini menawarkan perlindungan terhadap serangan Sesi Fixation khas dengan mengkonfigurasi apa yang berlaku pada sesi yang ada ketika pengguna cuba mengesahkannya lagi:

 ...

Konfigurasi Java yang sesuai:

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

Secara lalai, Spring Security mengaktifkan perlindungan ini (" migrateSession ") - pada pengesahan Sesi HTTP baru dibuat, yang lama tidak sah dan atribut dari sesi lama disalin.

Sekiranya ini bukan tingkah laku yang diingini, ada dua pilihan lain:

  • apabila " tidak ada " ditetapkan, sesi asal 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 semasa juga dapat diperoleh secara terprogram melalui Servlet API mentah :

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

10. Kesimpulannya

Dalam artikel ini, kami membincangkan pengurusan Sesi dengan Spring Security. Juga, Spring Reference mengandungi FAQ yang sangat baik mengenai Pengurusan Sesi.

Seperti biasa, kod yang disajikan dalam artikel ini terdapat di Github. Ini adalah projek berasaskan Maven, jadi mudah diimport dan dijalankan sebagaimana adanya.