מה זה CSRF?
חולשת CSRF – Cross-Site Request Forgery מאפשרת לתוקף לגנוב זהות משתמש דרך שליחת בקשות בשמו אל מול השרת שבהרבה מקרים אף יבדוק שהמשתמש מאומת.
למעשה, ההבדל בין חולשת CSRF לחולשת XSS עליה כתבנו במאמר אחר, הוא ש ב XSS ישנו ניצול של האמון שנותן המשתמש במותג/אתר בו הוא גולש. לעומת זאת ב- CSRF התוקף מנצל את האמון שהשרת נותן במשתמש ששלח את הבקשה.
במאמר זה אני אנסה לענות על השאלות הבאות:
- איך ניתן לנצל חולשת CSRF?
- כיצד ניתן להימנע ולהתגונן?
- איך נצרוך ונחזיר לשרת טוקן ייחודי לזיהוי?
מה הדרכים לניצול חולשת CSRF?
כדי לענות על שאלה זו צריך להבין תחילה באיזה מצב השרת שלנו חשוף להתקפה כזו.
ניצול קריאות GET
כל מפתח מן השורה יודע ששני סוגי הקריאות הנפוצות ביותר לשרת הן GET ו- POST.
הפירצה האפשרית והדי בסיסית הניתנת לניצול היא כאשר – השרת שלנו מקבל קריאות לשינוי מידע בבסיס הנתונים דרך קריאת GET.
דמיינו סיטואציה בה הגולש נכנס לאתר עם דומיין ומראה הדומה לאתר הבנק שלו ומיד ברגע הכניסה הועברו סכומי כסף לחשבון אחר, איך זה קרה אתם שואלים?
מסתבר שבעזרת תגית <img> פשוטה התוקף יכול לקרוא ל- url עם הפרמטרים המתאימים דרך ה- src ולהנחות את השרת לפעול בשם הלקוח האמיתי. למעשה, בטעינת התמונה נשלחים ערכי ה cookies של אותו דומיין מקורי של הבנק השמורים בדפדפן.
אומנם אי אפשר לגשת ל response של קריאה שחוזרת מתגית תמונה, אך זה לא מה שמעניין בפרקטיקה בתקיפה מסוג CSRF.

ולכן תמיד וודאו שלא ניתן לבצע כל שינוי במידע שלכם דרך קריאות GET.
דרך אגב, הדפדפן חוסם קריאות fetch או XHR עם דגל של credentials המשמש לשליחת Cookies של הדומיין המבוקש יחד עם הקריאה. הדפדפן יתריע על הגנה מפני CORS שאומר שלא ניתן להעביר מידע פרטי בין דומיינים שונים.

ניצול קריאות POST
מסתבר שגם קריאות מסוג POST אינן חסינות ממתקפת CSRF.
אחת הדרכים הנפוצות לבצע קריאות POST היא באמצעות טופס עם method=״POST״
ועם action שמופנה לדומיין שאותו נרצה לתקוף, למשל של הבנק.
במצב הנ״ל נצליח לבצע קריאת POST עם מידע שנשלח יחד עם ה Cookies. הסיבה היא שבפועל העברנו את המשתמש לכתובת אחרת שצוינה בטופס ולא ניסינו לקרוא את המידע הפרטי שלו בדרך.
כיצד ניתן להתגונן?
הימנעו מקריאות GET לשינוי מידע
כפי שרשמתי בחלק שעוסק על ניצול קריאות GET, מינעו משינוים שניתן לבצע על המידע שלכם דרך קריאות GET הניתנות לניצול בקלות.
חסמו דומיינים לא מורשים
ניתן לבדוק מאיזה origin (דומיין) הגיעה הקריאה. במידה והדומיין אינו מוגדר כמוכר/מורשה חסמו את הקריאה הזו.
השתדלו לעבוד עם JSON
וודאו שהשרת שלכם עובד רק עם קריאות המעבירות מידע דרך json, כלומר גוף הקריאה מכיל json עם המידע שנרצה להעביר לשרת.
הסיבה היא – שלא ניתן לשלוח קריאות עם האדר של Content-Type: application/json דרך טפסים. כפי שהדגמתי למעלה, בעזרת טופס ניתן לשלוח קריאות POST עם המידע הזדוני.
תעבדו עם CSRF Token
הדרך הבטוחה ביותר היא לעבוד עם CSRF Token. בעזרת הטוקן השרת מוודא שהקריאה נשלחה דרך האתר ומי שביצע אותה הוא משתמש מזוהה.
בפועל השרת יוצר את הטוקן ובמקביל משייך אותו לסשן של המשתמש המחובר.
גורם צד שלישי לא יכול לנחש טוקן שכזה משום שהוא ארוך ונבנה מתווים בצורה רנדומלית.
איך לצרוך CSRF Token?
במצב SPA
הרבה מאיתנו מפתחים את האפליקציות שלנו בסגנון של Single Page Apps מה שאומר שמשאיר את רינדור העמוד לדפדפן בזמן אמת ולאחר שנטענו קבצי האפליקציה.
אפליקציית SPA תצרוך את המידע שלה דרך API בשימוש עם Fetch API או אובייקט XHR.
לרוב, את הטוקן נקבל בהתחברות וההזדהות אל מול השרת. מאותו רגע נעביר אותו דרך ההאדרים של הבקשות שלנו.
הסטנדרט הוא העברה של הטוקן דרך הגדרת ערך בהאדר שנקרא – X-CSRF-TOKEN.
ישנם שרתים המחזירים את הטוקן עבור כל בקשה ובכך מרעננים אותו בצורה תחופה יותר לעומת פעם אחת ברגע ההתחברות.
במצב SSR
תרחיש לא פחות נפוץ הוא כאשר השרת אחראי על רינדור ה UI. כך השרת יכול להזריק בצורה ישירה את הטוקן אל תוך ה HTML ולאפשר לאפליקציה שלנו לצרוך ולהעביר אותו הלאה במידת הצורך.
למשל, הכנסת תגית meta ב head של האתר עם הערך של ה CSRF Token.
איך להעביר CSRF Token?
באמצעות קריאה אסינכרונית
כפי שציינתי בפיסקה למעלה נוכל להעביר את הטוקן דרך fetch או XHR ונגדיר האדרים בהתאם.
למשל, כך תראה קראית fetch שמעביר CSRF Token:
const csrfToken = getCookie('CSRF-TOKEN');
const headers = new Headers({
'X-CSRF-TOKEN': csrfToken
});
return fetch(‘https://example.com’, {
method: 'POST',
headers,
body: JSON.stringify({ /* SOME DATA */ })
});
באמצעות טופס
האמצעי השני שלנו להעברת הטוקן בתוך קריאה לשרת הוא שימוש בטופס, מה שנקרא Old School.
בצורה הזו נכניס שדה חבוי שמחזיק את הטוקן תחת שם ייחודי שהשרת מצפה לו.
להלן דוגמה של העברת הטוקן דרך שדה חבוי בטופס:
<form action="https://example.com" method="POST">
<input type="hidden" name="csrf" value="CSRF_TOKEN" />
<input type="text" name="credit_card" />
<button>Submit</button>
</form>
לסיכום
CSRF היא חולשה מסוכנת דרכה אפשר להערים על השרת ולבצע פעולות בשם המשתמש.
יחד עם זאת חשוב לציין, זו חולשה שכיום מכוסה ברוב המקרים כברירת מחדל. ההתגוננות מולה הפכה לסטנדרט בכל פריימוורק שאחראי על שינוי המידע בשרת.
אך אם שמירה על אבטחת הפרטיות של המשתמש שלכם מדירה שינה מעיניכם הקפידו להשתמש בהמלצות שרשמתי למעלה.