Sprievodca ochranou CSRF v jarnej bezpečnosti

1. Prehľad

V tomto tutoriáli sa budeme zaoberať útokmi CSRF na Cross-Site Request Forgery a o tom, ako im zabrániť pomocou Spring Security.

2. Dva jednoduché útoky CSRF

Existuje niekoľko foriem útokov CSRF - poďme si predstaviť niektoré z najbežnejších.

2.1. ZÍSKAJTE príklady

Zvážme nasledujúce ZÍSKAJTE žiadosť používaná prihlásenými používateľmi na prevod peňazí na konkrétny bankový účet “1234”:

ZÍSKAJTE //bank.com/transfer?accountNo=1234&amount=100

Ak chce útočník namiesto toho previesť peniaze z účtu obete na jeho vlastný účet - “5678” - musí prinútiť obeť, aby podala žiadosť:

ZÍSKAJTE //bank.com/transfer?accountNo=5678&amount=1000

Existuje niekoľko spôsobov, ako to dosiahnuť:

  • Odkaz: Útočník môže presvedčiť obeť, aby klikla na tento odkaz, napríklad aby uskutočnila prenos:
 Zobraziť obrázky mačiatok 
  • Obrázok: Útočník môže použiť značka s cieľovou adresou URL ako zdrojom obrázka - kliknutie teda nie je ani potrebné. Žiadosť sa automaticky vykoná po načítaní stránky:

2.2. Príklad POST

Ak musí byť hlavnou požiadavkou požiadavka POST - napríklad:

POST //bank.com/transfer accountNo = 1234 & suma = 100

Potom musí útočník nechať obeť bežať podobne:

POST //bank.com/transfer accountNo = 5678 & suma = 1000

Ani alebo bude v tomto prípade fungovať. Útočník bude potrebovať - nasledovne:

Formulár je však možné odoslať automaticky pomocou Javascriptu - a to nasledovne:

  ...

2.3. Praktická simulácia

Teraz, keď chápeme, ako vyzerá útok CSRF, simulujme tieto príklady v rámci jarnej aplikácie.

Začneme jednoduchou implementáciou radiča BankController:

@Controller verejná trieda BankController {private Logger logger = LoggerFactory.getLogger (getClass ()); @RequestMapping (value = "/ transfer", method = RequestMethod.GET) @ResponseBody public String transfer (@RequestParam ("accountNo") int accountNo, @RequestParam ("amount") konečná int suma) {logger.info ("Transfer do {} ", accountNo); ...} @RequestMapping (value = "/ transfer", method = RequestMethod.POST) @ResponseStatus (HttpStatus.OK) public void transfer2 (@RequestParam ("accountNo") int accountNo, @RequestParam ("amount") final int suma) {logger.info ("Prevod na {}", číslo účtu); ...}}

A máme tiež základnú stránku HTML, ktorá spúšťa bankový prevod:

 Prevod peňazí na čiastku čísla účtu John 

Toto je stránka hlavnej aplikácie bežiacej na pôvodnej doméne.

Upozorňujeme, že sme simulovali obidve a ZÍSKAJTE prostredníctvom jednoduchého odkazu ako aj a POST prostredníctvom jednoduchého .

Teraz - uvidíme ako stránka útočníka bude vyzerať takto:

  Zobraziť obrázky mačiatok 

Táto stránka bude fungovať na inej doméne - doméne útočníka.

Na záver spustime lokálne dve aplikácie - pôvodnú a útočnícku - a najskôr si otvorme pôvodnú stránku:

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

Potom vstúpime na stránku útočníka:

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

Pri sledovaní presných požiadaviek, ktoré pochádzajú z tejto stránky útočníka, dokážeme problémovú požiadavku okamžite spozorovať, naraziť na pôvodnú aplikáciu a úplne sa autentifikovať.

3. Jarná konfigurácia zabezpečenia

Aby sme mohli použiť Spring Security CSRF ochranu, najskôr sa musíme uistiť, že používame správne metódy HTTP pre čokoľvek, čo modifikuje stav (PATCH, POST, PUTa ODSTRÁNIŤ - nie ZÍSKAŤ).

3.1. Konfigurácia Java

Ochrana CSRF je predvolene povolené v konfigurácii Java. Stále ho môžeme deaktivovať, ak potrebujeme:

@Override protected void configure (HttpSecurity http) vyvolá výnimku {http .csrf (). Disable (); }

3.2. Konfigurácia XML

V staršej konfigurácii XML (pred Spring Security 4) bola ochrana CSRF predvolene vypnutá a mohli sme ju povoliť nasledovne:

 ...  

Začať z Jarná bezpečnosť 4.x - ochrana CSRF je štandardne povolená aj v konfigurácii XML; samozrejme ho môžeme kedykoľvek deaktivovať, ak potrebujeme:

 ...  

3.3. Parametre extra formulára

Nakoniec, s povolenou ochranou CSRF na strane servera, budeme musieť zahrnúť token CSRF aj do našich požiadaviek na strane klienta:

3.4. Používanie JSON

Ak používame JSON, nemôžeme odoslať token CSRF ako parameter; namiesto toho môžeme token odoslať do hlavičky.

Najprv budeme musieť zahrnúť token na našu stránku - a na to môžeme použiť metaznačky:

Potom zostrojíme hlavičku:

var token = $ ("meta [name = '_ csrf']"). attr ("obsah"); var header = $ ("meta [name = '_ csrf_header']"). attr ("obsah"); $ (document) .ajaxSend (function (e, xhr, options) {xhr.setRequestHeader (header, token);});

4. Test deaktivácie CSRF

Keď budeme mať všetko pripravené, urobíme nejaké testovanie.

Skúsme najskôr odoslať jednoduchú požiadavku POST, keď je vypnutá funkcia CSRF:

@ContextConfiguration (classes = {SecurityWithoutCsrfConfig.class, ...}) verejná trieda CsrfDisabledIntegrationTest predlžuje CsrfAbstractIntegrationTest {@Test verejná neplatnosť givenNotAuth_whenAddFoo_thenUnauthorized () obsahovala () "" content (createFoo ())). andExpect (status (). isUnauthorized ()); } @Test public void givenAuth_whenAddFoo_thenCreated () vyvolá výnimku {mvc.perform (post ("/ foos"). ContentType (MediaType.APPLICATION_JSON) .content (createFoo ()) .with (testUser ())) .andExpect (status () .isCreated ()); }}

Ako ste si mohli všimnúť, na udržanie bežnej pomocnej logiky testovania používame základnú triedu - CsrfAbstractIntegrationTest:

@RunWith (SpringJUnit4ClassRunner.class) @WebAppConfiguration verejná trieda CsrfAbstractIntegrationTest {@Autowired súkromný kontext WebApplicationContext; @Autowired private Filter springSecurityFilterChain; chránený MockMvc mvc; @Before public void setup () {mvc = MockMvcBuilders.webAppContextSetup (kontext). AddFilters (springSecurityFilterChain) .build (); } chránené RequestPostProcessor testUser () {návratový používateľ ("používateľ"). heslo ("userPass"). role ("USER"); } chránený reťazec createFoo () hodí JsonProcessingException {vrátiť nový ObjectMapper (). writeValueAsString (nový Foo (randomAlphabetic (6)))); }}

Upozorňujeme, že keď mal používateľ správne bezpečnostné poverenia, požiadavka bola úspešne vykonaná - neboli potrebné žiadne ďalšie informácie.

To znamená, že útočník môže jednoducho použiť ktorýkoľvek z predtým diskutovaných vektorov útoku na ľahké narušenie systému.

5. CSRF povolený test

Poďme povoliť ochranu CSRF a pozrime sa na rozdiel:

@ContextConfiguration (classes = {SecurityWithCsrfConfig.class, ...}) verejná trieda CsrfEnabledIntegrationTest rozširuje CsrfAbstractIntegrationTest {@Test public void givenNoCsrf_whenAddFoo_thenForbidden () hodí (). "" content (createFoo ()). with (testUser ())). andExpect (status (). isForbidden ()); } @Test public void givenCsrf_whenAddFoo_thenCreated () vyvolá výnimku {mvc.perform (post ("/ foos"). ContentType (MediaType.APPLICATION_JSON) .content (createFoo ()) .with (testUser ()). S (csrf ()) ). andExpect (status (). isCreated ()); }}

Teraz tento test používa inú konfiguráciu zabezpečenia - takú, ktorá má povolenú ochranu CSRF.

Teraz nebude požiadavka POST zlyhať, ak nebude zahrnutý token CSRF, čo samozrejme znamená, že skoršie útoky už nie sú možné.

Nakoniec si všimnite csrf () metóda v teste; toto vytvára a RequestPostProcessor ktorá automaticky vyplní platný token CSRF v žiadosti na účely testovania.

6. Záver

V tomto článku sme diskutovali o niekoľkých útokoch CSRF a o tom, ako im zabrániť v používaní Spring Security.

The úplná implementácia tohto tutoriálu nájdete v projekte GitHub - jedná sa o projekt založený na Maven, takže by malo byť ľahké ho importovať a spustiť tak, ako je.


$config[zx-auto] not found$config[zx-overlay] not found