Kas yra CSRF ir kodėl dviejų dalių apsauga
Tavo formos dabar POST'ina laimingai — ir tai yra pažeidžiamumas. Ši pamoka jį uždaro, ir tai darydama pataikysi į labiausiai neteisingai suprantamą klaidą Go web kūrime. Priversim tave į ją pataikyti sąmoningai, nes jos derinimas ir yra būdas iš tikro suprasti, ką CSRF apsauga daro.
Ataka. Esi prisijungęs prie SignFlow (tavo sesijos slapukas naršyklėje). Aplankai kažkokią nesusijusią svetainę — forumą, reklamą. Tas puslapis turi:
<form action="https://signflow.app/logout" method="post" id="x"></form>
<script>document.getElementById('x').submit()</script>
Naršyklė ją pateikia — ir automatiškai prideda tavo SignFlow sesijos slapuką, nes taip slapukai veikia. SignFlow mato galiojančią sesiją ir tave atjungia. Pakeisk /logout į „pakeisti mano el. paštą" tašką ir tai — paskyros perėmimas. Tai Cross-Site Request Forgery: kitas šaltinis sukelia autentifikuotą veiksmą naudodamas tavo slapuką. Vartotojas SignFlow nieko nepaspaudė.
Apsauga turi dvi puses, ir būtent šią dalį visi išmoksta tik pusiau.
- Slaptas žetonas. SignFlow įdeda atsitiktinį žetoną į slapuką ir reikalauja jį atkartoti paslėptame formos lauke kiekviename POST. Įsilaužėlio puslapis negali perskaityti tavo slapuko (
SameSite/HttpOnlypadeda) ir negali atspėti žetono, tad negali įdėti atitinkamo lauko. Tikros SignFlow formos jį neša; suklastotos — ne. - Origin/Referer patikra. Be žetono, middleware tikrina, kad užklausa atėjo iš paties SignFlow šaltinio. Tai pusė, kurią žmonės pamiršta — ir būtent ji tuoj tave įkąs.
Naudojam gorilla/csrf. Vienas middleware, csrf.Protect, užtikrina abi puses kiekvienam nesaugiam metodui. Formos įdeda žetoną per paslėptą gorilla.csrf.Token lauką.
Spąstai, kuriuos tuoj sutiksi. gorilla/csrf daro prielaidą, kad aptarnauja per HTTPS. Origin/Referer pusei jis reikalauja, kad užklausa įrodytų atėjusi iš to paties saugaus šaltinio — o paprasta http://localhost užklausa to įrodyti negali. Tad vos įjungęs apsaugą, tavo dev formos bus atmestos su pranešimu, kuris nieko iš to nepaaiškina. Įjungsim, pažiūrėsim, kaip lūžta, ir tik tada pataisysim — nes taisymas prasmingas tik pajutus problemą.
Ši pamoka:
- Pridėk
csrf.Protect(config gauna paslaptį,mainišveda raktą) — ir pateik formą, kad pataikytum į 403. - Diagnozuok, pridėk tik-dev plaintext išimtį, pridėk žetono lauką į kiekvieną formą ir žiūrėk, kaip veikia.