כיצד להתמודד עם התקפת CSRF באמצעות קוד PHP?
רשת האינטרנט היא רשת צעירה יחסית, ובהתאם הסטנדרטים של האבטחה בה הם די רופפים. עובדה שמאפשרת להאקרים להמציא שיטות שפוגעות באתרים ובגולשים בהם. במדריך זה אסביר על התקפה זדונית במיוחד ששמה CSRF , וכיצד ניתן להתמודד עמה.
התקפת CSRF (Cross Site Request Forgery) מאפשרת לתוקף לבצע פעולות על חשבון משתמש מזוהה, שעשה לוגאין לאתר. התקפת CSRF אפשרית בגלל שמשתמש שעשה לוגאין לאתר מזוהה על ידי עוגיות רשת (cookies) , שרצות על הדפדפן של המשתמש, ונשלחות חזרה לאתר, לשם זיהוי, עם כל פעולה. התוקף מנצל את העובדה הזו, ומפתה את הקורבן, שעשה לוגאין לאתר ומזוהה באמצעות ה-cookies, להריץ סקריפט שעושה באתר פעולות שרצויות לתוקף, כדוגמת, שינוי ססמת משתמש, ביצוע רכישות על חשבון המשתמש, והעברת כספים מהקורבן אל התוקף.
התקפת CSRF יכולה להתבצע באמצעות קישור תמים למראה, שהמשתמש לחץ עליו, או באמצעות תמונה או iframe במייל או בדף אינטרנט, שמסווים בתוכם סקריפט מזיק. תרחיש לדוגמה יכול להיות מייל שהקורבן מקבל, הכולל לינק שלחיצה עליו גורמת להעברת סכום של כסף מחשבונו של הקורבן אל חשבונו של התוקף. זה יכול לקרות במצב שבו במקביל ללחיצה על הלינק במייל, המשתמש גולש בחשבון הבנק שלו.
כדי להתמודד עם הבעיה, אפשר להשתמש ב טוקן (token), שזו מחרוזת אקראית מספיק וארוכה מכדי שהתוקף יוכל לזהות. את הטוקן יוצרים בכל פעם שנכנסים לדף ושומרים אותו ב-session ובשדה חבוי בטופס. כאשר הטופס מוגש, בודקים האם ערך השדה החבוי שווה לערך ה-session, ורק אם זה המצב מאפשרים את עיבוד הטופס. התוקף, מצידו, לא יכול לדעת מהו ערך הטוקן, ולכן ההתקפה תיכשל.
דוגמת הקוד המצורפת מדגימה כיצד ניתן לייצר טוקן, ולהשתמש בו למניעת CSRF.
טופס ה-HTML
אנו משלבים את הטוקן בתוך שדה חבוי בטופס.
<html>
<form action="" method="post">
<input type="text" name="text">
<input type="hidden" value="<?php echo $token; ?>" name="token">
<input type="submit" value="send" name="submit">
</form>
</html>
המחלקה Token
המחלקה Token כוללת את המתודות הבאות:
מתודה create שיוצרת מחרוזת אקראית באורך הרצוי לנו (ברירת המחדל היא 50 תווים), ומאחסנת אותה במשתנה $token.
מתודה toSession, שמאחסנת את הטוקן ב-session.
מתודה check, שמקבלת כארגומנט את הערך של הטוקן בשדה החבוי בטופס, ומחזירה true, אם הערך שווה לערך ה-session, או false.
class Token
{
// Store the token value.
protected $token = false;
// Create a random token by the specified length.
public function create($length=50)
{
$randStr = '';
$chars = array_merge(range(0,9), range('a','z'),range('A','Z'),array('-','_','+','$','@','^'));
for ($i = 0; $i < $length; $i++) {
$randStr .= $chars[array_rand($chars)];
}
$this->token = $randStr;
return $this;
}
// Make a session out of the token.
public function toSession()
{
return $_SESSION['token'] = $this->token;
}
// Check if the value for the token field in the form
// matches the value of the session.
public function check($str)
{
if(!isset($_SESSION['token'])) return false;
if($str !== $_SESSION['token']) return false;
return true;
}
}
עיבוד הטופס
מעל לטופס נוסיף את החלק שמעבד את הטופס, ובמסגרתו:
1. יוצרים מופע של הקלאס Token.
2. כשהטופס מוגש, מושווה הערך של ה-Token מהטופס עם ערך ה-session, ומסופקת תגובה בהתאם.
3. יוצרים את הטוקן, ומזינים את ערכו ל-session.
<?php
session_start();
require 'class/Token.php ';
// Instantiate the class.
$tok = new Token();
// If the form was submitted.
if(isset($_POST['submit']))
{
// Check the value of the token embedded in the form
// against the value of the session,
// and provide indicative statement.
if($tok->check($_POST['token']))
{
echo "ok";
}
else
{
echo "stop messing with my tokens.";
}
}
// Create the token and store it in a session.
$token = $tok->create()->toSession();
?>
<html>
<form action="" method="post">
<input type="text" name="text">
<input type="hidden" value="<?php echo $token; ?>" name="token">
<input type="submit" value="send" name="submit">
</form>
</html>
שימו לב, שהפתרון שאני מציע פה מספק אבטחה מאוד חזקה מפני תקיפות CSRF, אבל יש דרך יותר חזקה שאפשרית על אתרים שרצים בסביבת HTTPS, ובמקרה שאתם מעוניינים להגן על אתר כזה, רצוי לבדוק את הנושא עם המתכנת שלכם.
אהבתם? לא אהבתם? דרגו!
0 הצבעות, ממוצע 0 מתוך 5 כוכבים
המדריכים באתר עוסקים בנושאי תכנות ופיתוח אישי. הקוד שמוצג משמש להדגמה ולצרכי לימוד. התוכן והקוד המוצגים באתר נבדקו בקפידה ונמצאו תקינים. אבל ייתכן ששימוש במערכות שונות, דוגמת דפדפן או מערכת הפעלה שונה ולאור השינויים הטכנולוגיים התכופים בעולם שבו אנו חיים יגרום לתוצאות שונות מהמצופה. בכל מקרה, אין בעל האתר נושא באחריות לכל שיבוש או שימוש לא אחראי בתכנים הלימודיים באתר.
למרות האמור לעיל, ומתוך רצון טוב, אם נתקלת בקשיים ביישום הקוד באתר מפאת מה שנראה לך כשגיאה או כחוסר עקביות נא להשאיר תגובה עם פירוט הבעיה באזור התגובות בתחתית המדריכים. זה יכול לעזור למשתמשים אחרים שנתקלו באותה בעיה ואם אני רואה שהבעיה עקרונית אני עשוי לערוך התאמה במדריך או להסיר אותו כדי להימנע מהטעיית הציבור.
שימו לב! הסקריפטים במדריכים מיועדים למטרות לימוד בלבד. כשאתם עובדים על הפרויקטים שלכם אתם צריכים להשתמש בספריות וסביבות פיתוח מוכחות, מהירות ובטוחות.
המשתמש באתר צריך להיות מודע לכך שאם וכאשר הוא מפתח קוד בשביל פרויקט הוא חייב לשים לב ולהשתמש בסביבת הפיתוח המתאימה ביותר, הבטוחה ביותר, היעילה ביותר וכמובן שהוא צריך לבדוק את הקוד בהיבטים של יעילות ואבטחה. מי אמר שלהיות מפתח זו עבודה קלה ?
השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.