Útmutató a CSRF védelméhez a tavaszi biztonságban

1. Áttekintés

Ebben az oktatóanyagban megvitatjuk a webhelyek közötti kérelmek hamisítását célzó CSRF-támadásokat és annak megakadályozását, hogy miként lehet őket használni a Spring Security használatával.

2. Két egyszerű CSRF támadás

A CSRF-támadásoknak többféle formája létezik - beszéljünk a leggyakoribbakról.

2.1. GET Példák

Vegyük fontolóra a következőket KAP kérelem, amelyet a bejelentkezett felhasználók használnak pénz átutalására meghatározott bankszámlára “1234”:

GET //bank.com/transfer?accountNo=1234&amount=100

Ha a támadó ehelyett pénzt akar átutalni az áldozatok számlájáról a saját számlájára - “5678” - meg kell indítania az áldozatot a kérés kiváltására:

GET //bank.com/transfer?accountNo=5678&amount=1000

Ennek többféle módja van:

  • Link: A támadó meg tudja győzni az áldozatot, hogy kattintson erre a linkre, például az átadás végrehajtásához:
 Mutasd a cicák képeit 
  • Kép: A támadó használhat egy címke a kép URL-jével képforrásként - így a kattintásra még csak nincs is szükség. A kérés automatikusan végrehajtásra kerül, amikor az oldal betöltődik:

2.2. POST Példa

Ha a fő kérelemnek POST-kérelemnek kell lennie - például:

POST //bank.com/transfer accountNo = 1234 és összeg = 100

Ezután a támadónak az áldozatnak hasonlót kell futtatnia:

POST //bank.com/transfer accountNo = 5678 és összeg = 1000

Sem a vagy a működni fog ebben az esetben. A támadónak szüksége lesz a - alábbiak szerint:

Az űrlap azonban automatikusan beküldhető a Javascript segítségével - az alábbiak szerint:

  ...

2.3. Gyakorlati szimuláció

Most, hogy megértettük, hogyan néz ki a CSRF támadás, szimuláljuk ezeket a példákat egy Spring alkalmazásban.

Kezdjük egy egyszerű vezérlő implementációval - a BankController:

@Controller public class BankController {private Logger logger = LoggerFactory.getLogger (getClass ()); @RequestMapping (value = "/ transfer", method = RequestMethod.GET) @ResponseBody public String transfer (@RequestParam ("accountNo") int accountNo, @RequestParam ("összeg") final int summa) {logger.info ("Transfer ide: {} ", accountNo); ...} @RequestMapping (value = "/ transfer", method = RequestMethod.POST) @ResponseStatus (HttpStatus.OK) public void transfer2 (@RequestParam ("accountNo") int accountNo, @RequestParam ("összeg") final int összeg) {logger.info ("Átutalás {}" -ra, accountNo); ...}}

És legyen egy alapvető HTML oldalunk is, amely beindítja a banki átutalási műveletet:

 Pénz átutalása John számlaszámra 

Ez a fő alkalmazás oldala, amely az origó tartományban fut.

Ne feledje, hogy mindkettőt szimuláltuk a KAP egy egyszerű linken keresztül, valamint a POST egy egyszerűn keresztül .

Most - nézzük meg, hogyan a támadó oldal a következőképpen nézne ki:

  Mutasd a cicák képeit 

Ez az oldal egy másik tartományban fog futni - a támadó tartományban.

Végül futtassuk helyileg a két alkalmazást - az eredeti és a támadóalkalmazást, és először nyissuk meg az eredeti oldalt:

//localhost:8081/spring-rest-full/csrfHome.html

Ezután nyissuk meg a támadó oldalt:

//localhost:8081/spring-security-rest/api/csrfAttacker.html

Az ezen támadóoldalról származó pontos kérelmek nyomon követésével azonnal észrevehetjük a problémás kérést, az eredeti alkalmazást eltalálva és teljesen hitelesítve.

3. Tavaszi biztonsági konfiguráció

A Spring Security CSRF védelem használatához először meg kell győződnünk arról, hogy a megfelelő HTTP metódusokat használjuk mindenhez, ami módosítja az állapotot (TAPASZ, POST, PUT, és TÖRLÉS - nem GET).

3.1. Java konfiguráció

A CSRF védelem alapértelmezés szerint engedélyezve van a Java konfigurációban. Még mindig letilthatjuk, ha szükségünk van:

A @Orride protected void configure (HttpSecurity http) a Kivételt dobja: {http .csrf (). Disable (); }

3.2. XML konfiguráció

A régebbi XML konfigurációban (a Spring Security pre 4 előtt) a CSRF védelem alapértelmezés szerint le volt tiltva, és a következőképpen engedélyezhettük:

 ...  

Kezdve Tavaszi biztonság 4.x - a CSRF védelem alapértelmezés szerint engedélyezett az XML konfigurációban is; természetesen továbbra is letilthatjuk, ha:

 ...  

3.3. Extra űrlapparaméterek

Végül, ha a szerver oldalon engedélyezve van a CSRF védelem, akkor a kliens oldalon is meg kell adnunk a CSRF tokent a kéréseinkben:

3.4. A JSON használata

Nem küldhetjük el a CSRF tokent paraméterként, ha JSON-t használunk; ehelyett beküldhetjük a tokent a fejlécen belül.

Először fel kell tennünk a tokent az oldalunkra - ehhez pedig metacímkéket használhatunk:

Ezután elkészítjük a fejlécet:

var token = $ ("meta [név = '_ csrf']"). attr ("tartalom"); var header = $ ("meta [név = '_ csrf_header']"). attr ("tartalom"); $ (document) .ajaxSend (function (e, xhr, options) {xhr.setRequestHeader (fejléc, token);});

4. CSRF letiltott teszt

Ha mindez a helyén van, elmozdulunk egy kis tesztelésre.

Próbálkozzunk először egy egyszerű POST-kérelem benyújtásával, amikor a CSRF le van tiltva:

A @ContextConfiguration (class = {SecurityWithoutCsrfConfig.class, ...}) nyilvános osztály CsrfDisabledIntegrationTest kiterjeszti a CsrfAbstractIntegrationTest {@Test public void givenNotAuth_whenAddFoo_thenUnauthorized () Dobja Exception {MediaTV. content (createFoo ())) .andExpect (status (). isNehonos ()); } @Test public void givenAuth_whenAddFoo_thenCreated () dobja a Kivételt {mvc.perform (post ("/ foos"). ContentType (MediaType.APPLICATION_JSON) .content (createFoo ()) .with (testUser ())) .Expect (status () .létrehozva()); }}

Mint észrevehette, egy alaposztályt használunk a közös tesztelési segítő logika - a CsrfAbstractIntegrationTest:

@RunWith (SpringJUnit4ClassRunner.class) @WebAppConfiguration nyilvános osztály CsrfAbstractIntegrationTest {@Autowired private WebApplicationContext kontextus; @Autowired privát szűrő springSecurityFilterChain; védett MockMvc mvc; @A nyilvános void beállítása előtt () {mvc = MockMvcBuilders.webAppContextSetup (context) .addFilters (springSecurityFilterChain) .build (); } védett RequestPostProcessor testUser () {return user ("user"). jelszó ("userPass"). szerepek ("USER"); } védett String createFoo () dobja a JsonProcessingException {return new ObjectMapper () -t. writeValueAsString (new Foo (randomAlphabetic (6))); }}

Vegye figyelembe, hogy amikor a felhasználónak megfelelő biztonsági adatai voltak, a kérés sikeresen végrehajtásra került - semmilyen további információ nem volt szükséges.

Ez azt jelenti, hogy a támadó egyszerűen használhatja a korábban tárgyalt támadási vektorok bármelyikét a rendszer egyszerű veszélyeztetése érdekében.

5. CSRF engedélyezett teszt

Most engedélyezzük a CSRF-védelmet, és lássuk a különbséget:

A @ContextConfiguration (class = {SecurityWithCsrfConfig.class, ...}) nyilvános osztály CsrfEnabledIntegrationTest kiterjeszti a CsrfAbstractIntegrationTest {@Test public void givenNoCsrf_whenAddFoo_thenForbidden () Dobja Exception {mvc.per. content (createFoo ()) .with (testUser ())) .andExpect (status (). isForbidden ()); } @Test public void givenCsrf_whenAddFoo_thenCreated () dobja a Kivételt {mvc.perform (post ("/ foos"). ContentType (MediaType.APPLICATION_JSON) .content (createFoo ()) .with (testUser ()). (Csrf ()) ) .ésExpect (status (). isCreated ()); }}

Most, hogy ez a teszt egy másik biztonsági konfigurációt használ - azt, amelyen engedélyezve van a CSRF védelem.

Most a POST kérés egyszerűen meghiúsul, ha a CSRF tokent nem tartalmazza, ami természetesen azt jelenti, hogy a korábbi támadások már nem választhatók.

Végül vegye észre a csrf () módszer a tesztben; ez létrehozza a RequestPostProcessor amely automatikusan feltölti az érvényes CSRF tokent a kérelemben tesztelési célokra.

6. Következtetés

Ebben a cikkben megvitattunk néhány CSRF-támadást és azt, hogy miként lehet megakadályozni őket a Spring Security használatával.

A teljes végrehajtása ennek az oktatóanyagnak a GitHub projektjében található meg - ez egy Maven-alapú projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.