Hoparner
September 6, 2025

CSRF – Spring Security-ի մանրամասները

Cross-site request forgery (CSRF) հարձակման ժամանակ հարձակվողը խաբում է օգտվողին կամ բրաուզերին՝ վնասակար կայքից թիրախային կայքին HTTP հարցում կատարելու համար։ Հարցումը ներառում է օգտատիրոջ հավատարմագրերը եւ ստիպում է սերվերին իրականացնել ինչ-որ վնասակար գործողություն՝ մտածելով, որ օգտվողը մտադիր է դա անել.

Ակնարկ

Կայքը սովորաբար հատուկ գործողություններ է կատարում օգտատիրոջ անունից, օրինակ՝ ապրանք գնելը կամ պայմանավորվածություն ձեռք բերելը՝ ստանալով HTTP հարցում օգտագործողի բրաուզերից, հաճախ պարամետրերով, որոնք մանրամասնորեն նկարագրում են կատարվող գործողությունը։ Ապահովելու համար, որ հարցումն իսկապես գալիս է տվյալ օգտագործողից, սերվերը ակնկալում է, որ հարցումը ներառի Հավատարմագրեր օգտատիրոջ համար՝ օրինակ՝ cookie, որը պարունակում է օգտատիրոջ նիստի ID-ն.

Ստորեւ բերված օրինակում օգտատերը նախապես մուտք է գործել իր բանկ, եւ բրաուզերը պահպանել է օգտատիրոջ համար սեսիոն cookie: Էջը պարունակում է <form> տարր, որը հնարավորություն է տալիս օգտատիրոջը փոխանցել գումար այլ անձի: Երբ օգտվողը ներկայացնում է ձեւը, զննարկիչը ուղարկում է POST հարցումը սերվերին, ներառյալ ձեւի տվյալները: Եթե օգտվողը մուտք է գործել, հարցումը ներառում է օգտատիրոջ cookie-ն: Սերվերը վավերացնում է cookie-ն եւ կատարում է հատուկ գործողություն՝ տվյալ դեպքում՝ գումար փոխանցում:

Այս ուղեցույցում մենք կանվանենք այսպիսի խնդրանք, որն իրականացնում է ինչ-որ հատուկ գործողություն, Վիճակը փոխող հայց.

CSRF հարձակման ժամանակ հարձակվողը ստեղծում է ձեւ պարունակող կայք։ Ձեւը action հատկանիշ սահմանված է բանկի կայքում, եւ ձեւը պարունակում է թաքնված մուտքային դաշտեր, որոնք նմանակում են բանկի դաշտերը:

<form action="https://my-bank.example.org/transfer" method="POST">
  <input type="hidden" name="recipient" value="attacker" />
  <input type="hidden" name="amount" value="1000" />
</form>

Էջը պարունակում է նաեւ JavaScript, որը ներկայացնում է ձեւը էջի բեռնման ժամանակ:

const form = document.querySelector("form");
form.submit();

Երբ օգտատերը այցելում է էջ, բրաուզերը ձեւաթուղթը ներկայացնում է բանկի կայք: Քանի որ օգտատերը մուտք է գործել իր բանկ, հարցումը կարող է ներառել օգտատիրոջ իրական cookie-ն, ուստի բանկի սերվերը հաջողությամբ վավերացնում է հարցումը եւ փոխանցում գումարը:

Կան այլ եղանակներ, որոնցով հարձակվողը կարող է հրապարակել խաչաձեւ խնդրանքի կեղծիք։ Օրինակ, եթե կայքն օգտագործում է GET գործողությունը իրականացնելու խնդրանքով, ապա հարձակվողը կարող է խուսափել ընդհանրապես ձեւ օգտագործելուց եւ կարող է իրականացնել հարձակումը՝ ուղարկելով օգտվողին հղում դեպի մի էջ, որը պարունակում է այսպիսի նշում:

<img
  src="https://my-bank.example.org/transfer?recipient=attacker&amount=1000" />

Երբ օգտվողը բեռնում է էջը, բրաուզերը փորձում է ստանալ պատկերի ռեսուրսը, որն իրականում գործարքի հարցումն է.

Ընդհանուր առմամբ, CSRF հարձակումը հնարավոր է, եթե ձեր կայքը:

  • Օգտագործում է HTTP հարցումները՝ սերվերի որոշակի վիճակը փոխելու համար.
  • Օգտագործում է միայն բլիթներ՝ հաստատելու համար, որ հարցումը եկել է վավերացված օգտվողից.
  • Օգտագործում է միայն պարամետրերը հարցման մեջ, որոնք հարձակվողը կարող է կանխատեսել.

Պաշտպանություն ԿՍՊՀ-ի դեմ

Այս բաժնում մենք կներկայացնենք երեք այլընտրանքային պաշտպանություն CSRF-ի դեմ եւ չորրորդ պրակտիկան, որը կարող է օգտագործվել մյուսներից որեւէ մեկի համար խորը պաշտպանություն ապահովելու համար.

  • Առաջին առաջնային պաշտպանությունն այն է, որ Օգտագործել CSRF նշաններ էջում տեղադրված: Սա ամենատարածված մեթոդն է, եթե դուք տրամադրում եք վիճակը փոխող հարցումներ ձեւի տարրերից, ինչպես վերը նշված օրինակում.
  • Երկրորդը՝ Օգտագործել Վերցնել մետատվյալները HTTP վերնագրեր՝ ստուգելու համար, թե արդյոք վիճակը փոխող հարցումը տրվում է խաչմերուկում, թե ոչ.
  • Երրորդն այն է, որ ապահովենք, որ պետությունը փոխող խնդրանքները ոչ Simple Requests, այնպես, որ խաչաձեւ ծագման հարցումները արգելափակվեն լռելյայնի։ Այս մեթոդը տեղին է, եթե դուք տրամադրում եք վիճակը փոխող հարցումներ JavaScript API-ներից, ինչպիսիք են fetch().

Վերջում կքննարկենք the SameSite Cookie հատկանիշ, որը կարող է օգտագործվել նախորդ մեթոդներից որեւէ մեկի հետ միասին խորը պաշտպանություն ապահովելու համար.

CSRF նշաններ

Այս պաշտպանության մեջ, երբ սերվերը սպասարկում է էջը, այն էջում ներմուծում է անկանխատեսելի արժեք, որը կոչվում է CSRF token։ Այնուհետեւ, երբ օրինական էջը ուղարկում է վիճակը փոխող հարցումը սերվերին, այն ներառում է CSRF token-ը HTTP հարցում։ Այնուհետեւ սերվերը կարող է ստուգել նշանի արժեքը եւ իրականացնել հարցումը միայն այն դեպքում, եթե այն համապատասխանում է։ Քանի որ հարձակվողը չի կարող կռահել նշանի արժեքը, նրանք չեն կարող հաջող կեղծիք կատարել։ Նույնիսկ եթե հարձակվողը հայտնաբերում է նշան այն օգտագործելուց հետո, հարցումը չի կարող կրկնվել, եթե նշանը փոխվում է ամեն անգամ.

Ձեւաթղթերի ներկայացման համար CSRF նշանը սովորաբար ներառվում է թաքնված ձեւի դաշտում, այնպես որ ձեւը ներկայացնելիս այն ավտոմատ կերպով ուղարկվում է սերվեր՝ ստուգելու համար.

JavaScript API-ի համար, ինչպիսիք են fetch(), token-ը կարող է տեղադրվել cookie-ում կամ տեղադրվել էջում, իսկ JavaScript-ը հանում է արժեքը եւ ուղարկում այն որպես լրացուցիչ վերնագիր.

Ժամանակակից վեբ շրջանակները սովորաբար ունեն ներկառուցված աջակցություն CSRF թոքենների համար, օրինակ, Ջանգո հնարավորություն է տալիս Ձեզ պաշտպանել ձեւերը՝ օգտագործելով csrf_token tag. Սա ստեղծում է լրացուցիչ թաքնված ձեւի դաշտ, որը պարունակում է նշանը, որը շրջանակը ստուգում է սերվերի վրա.

Այս պաշտպանությունից օգտվելու համար դուք պետք է հասկանաք ձեր կայքի բոլոր տեղերը, որտեղ օգտագործում եք պետությունը փոխող HTTP հարցումները, եւ համոզվեք, որ օգտագործում եք ձեր ընտրած շրջանակի պաշտպանությունը.

Վերցնել մետատվյալները

Fetch մետատվյալները HTTP հարցման վերնագրերի հավաքածու է, որոնք ավելացվել են բրաուզերի կողմից, որոնք լրացուցիչ տեղեկատվություն են տրամադրում HTTP հարցման համատեքստի մասին։ Սպասարկիչը կարող է օգտագործել այս վերնագրերը՝ որոշելու համար, թե արդյոք պետք է թույլատրել հարցումը, թե ոչ.

CSRF-ի համար առավել կարեւոր է Sec-Fetch-Site վերնագիր, որը սերվերին ասում է, թե արդյոք այս հարցումը նույն ծագման, նույն կայքի, խաչմերուկի կամ նախաձեռնված է անմիջապես օգտատիրոջ կողմից։ Սերվերը կարող է օգտագործել այս տեղեկատվությունը՝ թույլատրելու խաչաձեւ ծագման հարցումները կամ արգելափակելու դրանք որպես պոտենցիալ CSRF հարձակումներ.

Օրինակ՝ սա էքսպրես Կոդը թույլատրում է միայն նույն կայքի եւ նույն ծագման հարցումները:

app.post("/transfer", (req, res) => {
  const secFetchSite = req.headers["sec-fetch-site"];
  if (secFetchSite === "same-origin" || secFetchSite === "same-site") {
    console.log("allowed");
    // Update state
  } else {
    console.log("denied");
    // Don't update state
  }
});

Տես Բերել մետատվյալների հարցման վերնագիր Fetch մետատվյալների վերնագրերի ամբողջական ցանկի համար, եւ Պաշտպանեք ձեր ռեսուրսները վեբ հարձակումներից՝ Fetch Metadata-ի միջոցով այս հատկությունն օգտագործելու ուղեցույցի համար.

Խուսափել պարզ հարցումներից

Վեբ բրաուզերները տարբերում են երկու տեսակի HTTP հարցումներ: պարզ Հարցումներ եւ այլ խնդրանքներ.

Պարզ հարցումներ, որոնք այն հարցումն են, որը բխում է <form> տարրերի ներկայացումը, կարող է կատարվել խաչաձեւ ծագում՝ առանց արգելափակման։ Քանի որ ձեւաթղթերը կարողացել են կատարել խաչաձեւ ծագման հարցումներ ինտերնետի վաղ օրերից, համատեղելիության համար կարեւոր է, որ նրանք դեռ կարողանան կատարել խաչաձեւ ծագման հարցումներ։ Ահա թե ինչու մենք պետք է կիրառենք այլ ռազմավարություններ ձեւերը CSRF-ից պաշտպանելու համար, օրինակ՝ CSRF token օգտագործելու համար.

Այնուամենայնիվ, վեբ հարթակի այլ մասեր, մասնավորապես՝ JavaScript API-ները, ինչպիսիք են fetch(), կարող է կատարել տարբեր տեսակի հարցումներ (օրինակ՝ հարցումներ, որոնք սահմանում են մաքսային վերնագրեր), եւ այդ հարցումները լռելյայն չեն թույլատրվում խաչաձեւ ծագում, ուստի CSRF հարձակումը հաջողության չի հասնի.

Այսպիսով, կայք, որն օգտագործում է fetch() կամ XMLHttpRequest կարող է պաշտպանվել CSRF-ից՝ ապահովելով, որ պետությունը փոխող խնդրանքները, որոնք նա տալիս է, երբեք պարզ հարցումներ չլինեն.

Օրինակ՝ հարցման կարգավորումը Content-Type դեպի "application/json" կխանգարի այն վերաբերվել պարզ խնդրանքի պես:

fetch("https://my-bank.example.org/transfer", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ recipient: "joe", amount: "100" }),
});

Նմանապես, հարցման վրա մաքսային վերնագիր սահմանելը կխանգարի այն վերաբերվել պարզ հարցման պես:

fetch("https://my-bank.example.org/transfer", {
  method: "POST",
  headers: {
    "X-MY-BANK-ANTI-CSRF": 1,
  },
  body: JSON.stringify({ recipient: "joe", amount: "100" }),
});

Վերնագրի անունը կարող է լինել ցանկացած բան, քանի դեռ այն չի հակասում ստանդարտ վերնագրերին.

Այնուհետեւ սերվերը կարող է ստուգել վերնագրի գոյությունը. եթե այն գոյություն ունի, ապա սերվերը գիտի, որ հարցումը չի դիտվել որպես պարզ հարցում.

Ոչ պարզ հարցումներ եւ CORS

Մենք ասել ենք, որ ոչ պարզ հարցումները լռելյայն չի ուղարկվել խաչաձեւ ծագում։ Բռնելն այն է, որ Cross-Origin Resource Sharing (CORS)) Արձանագրությունը թույլ է տալիս կայքին թուլացնել այս սահմանափակումը.

Մասնավորապես, ձեր կայքը խոցելի կլինի որոշակի ծագման CSRF հարձակման համար, եթե դրա պատասխանը պետությունը փոխող խնդրանքին ներառում է:

Պաշտպանությունը խորությամբ. SameSite թխվածքաբլիթներ

the SameSite cookie ատրիբուտը որոշակի պաշտպանություն է ապահովում CSRF հարձակումներից։ Դա լիարժեք պաշտպանություն չէ եւ լավագույնս դիտարկվում է որպես մյուս պաշտպանություններից մեկի լրացում, որը որոշակի չափով պաշտպանություն է ապահովում.

Այս հատկանիշը վերահսկում է, երբ բրաուզերին թույլատրվում է ներառել cookie-ն խաչմերուկային հարցման մեջ: Այն ունի երեք հնարավոր արժեք: None, Lax եւ Strict.

the Strict արժեքն առաջարկում է առավելագույն պաշտպանություն. եթե այս հատկանիշը սահմանված է, բրաուզերը չի ներառի cookie-ն որեւէ խաչաձեւ հարցման մեջ: Այնուամենայնիվ, սա ստեղծում է օգտագործելիության խնդիր. եթե օգտվողը մուտք է գործել ձեր կայք եւ հետեւում է ձեր կայքի հղումին այլ կայքից, ապա ձեր թխուկները չեն ներառվի, եւ օգտվողը չի ճանաչվի, երբ նրանք հասնեն ձեր կայք.

the Lax արժեքը թուլացնում է այս սահմանափակումը. Cookie-ները ներառված են խաչաձեւ կայքերի հարցումներում, եթե կիրառվում են հետեւյալ երկու պայմանները:

  • Խնդրանքը վերին մակարդակի զննարկման համատեքստի կողմնորոշումն էր.
  • Խնդրանքը օգտագործել է Անվտանգ մեթոդը՝ մասնավորապես՝, GET անվտանգ է, բայց POST Չէ.

Այնուամենայնիվ,, Lax առաջարկում է զգալիորեն ավելի թույլ պաշտպանություն, քան Strict:

  • Հարձակվողը կարող է խթանել վերին մակարդակի նավիգացիան։ Օրինակ՝ այս հոդվածի սկզբում մենք ցույց ենք տալիս CSRF հարձակումը, որի ժամանակ հարձակվողը ձեւաթուղթ է ներկայացնում թիրախին. սա համարվում է վերին մակարդակի նավիգացիա։ Եթե ձեւաթուղթը ներկայացվել է GET, ապա խնդրանքը դեռ ներառում է թխվածքաբլիթներ SameSite=Lax.
  • Նույնիսկ եթե սերվերը ստուգում է, որ հարցումը չի ուղարկվել օգտագործելով GET, Որոշ վեբ շրջանակներ աջակցում են «մեթոդի չեղարկմանը»: Սա հնարավորություն է տալիս հարձակվողին ուղարկել հարցում՝ օգտագործելով GET բայց թող այն սերվերին երեւա այնպես, կարծես օգտագործվում է POST.

Որպես ընդհանուր ուղեցույց, ուրեմն, դուք պետք է փորձեք օգտագործել Strict որոշ թխվածքաբլիթների եւ Lax Ուրիշների համար:

  • Lax քուքիների համար, որոնք դուք կօգտագործեք որոշելու համար, թե արդյոք մուտք գործած օգտվողին պետք է ցույց տրվի էջ
  • Strict քուքիների համար, որոնք դուք կօգտագործեք պետությունը փոխող հարցումների համար, որոնք չեք ցանկանում թույլատրել խաչաձեւ կայքը.

Մեկ այլ խնդիր SameSite հատկանիշն այն է, որ այն պաշտպանում է ձեզ դիմումներից այլ Կայք, ոչ այլ Ծագում. Սա ավելի ազատ պաշտպանություն է, քանի որ (օրինակ՝) https://foo.example.org եւ https://bar.example.org համարվում են նույն վայրը, թեեւ տարբեր ծագում ունեն։ Արդյունավետորեն, եթե դուք ապավինում եք նույն կայքի պաշտպանությանը, դուք պետք է վստահեք ձեր կայքի բոլոր ենթադոմեյններին.

Տես SameSite cookie-ի սահմանափակումների շրջանցում սահմանափակումների վերաբերյալ առավել մանրամասն SameSite.

Պաշտպանության ամփոփիչ ստուգաթերթ

Մենք կարող ենք ամփոփել վերոնշյալ պաշտպանությունները հետեւյալ կերպ:

  • Հասկանալ, թե ձեր կայքում որտեղ եք իրականացնում պետությունը փոխող հարցումները, որոնք օգտագործում են նիստի բլիթներ՝ ստուգելու համար, թե որ օգտվողն է տվել հարցումը.
  • Իրականացնել սույն փաստաթղթում նկարագրված առաջնային պաշտպանություններից առնվազն մեկը:
    • Եթե դուք օգտագործում եք <form> տարրեր այս հարցումները ներկայացնելու համար, համոզվեք, որ օգտագործում եք վեբ շրջանակ՝ CSRF tokenների աջակցությամբ, եւ օգտագործեք այն.
    • Եթե դուք օգտագործում եք JavaScript API-ներ, ինչպիսիք են fetch() կամ XMLHttpRequest պետությունը փոխող հարցումներ ներկայացնելու համար, համոզվել, որ դրանք պարզ հարցումներ չեն,.
    • Ինչ մեխանիզմ էլ օգտագործեք հարցումներ կատարելու համար, մտածեք օգտագործել Fetch մետատվյալները՝ խաչաձեւ կայքերի հարցումները չթույլատրելու համար.
  • Խուսափեք օգտագործելուց GET պետության փոփոխության հարցումներ տրամադրելու մեթոդ.
  • Սահմանել SameSite ատրիբուտ՝ նիստի թխուկների համար Strict եթե կարող եք, թե՞ Lax եթե պետք է.