Ú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.