מדריך מקיף לפתרון בעיית אי-שליחת עוגיות בבקשות בין-דומיין (CORS)
אם נתקלתם בתרחיש שבו השרת מגדיר את העוגיה כראוי (נראה בתגובת הדפדפן), אך בבקשות עוקבות הדפדפן אינו מחזיר את העוגיה לשרת, מדריך זה מיועד עבורכם. בעיה זו מתרחשת כמעט תמיד כאשר הצד הקדמי והאחורי של הפרויקט שלכם נמצאים בשני דומיינים או פורטים שונים — לדוגמה, הצד הקדמי ב-app.example.com וה-API ב-api.example.com.
למה זה קורה?
דפדפנים מודרניים מטילים שתי מדיניות אבטחה מחמירות כדי למנוע התקפות CSRF וגניבת הפעלות (Session Hijacking):
- מדיניות CORS: כברירת מחדל, הדפדפן אינו מאפשר לבקשות בין-דומיין לכלול אישורים (כגון עוגיות) אלא אם השרת מתיר זאת במפורש.
- מדיניות SameSite: החל מ-Chrome 80, עוגיות מטופלות כברירת מחדל עם התנהגות
SameSite=Lax, כלומר הן לא ישלחו בבקשות בין-דומיין אלא אם יוגדרו במפורש עםSameSite=None.
הנקודה החשובה היא שכדי לפתור בעיה זו, יש להגדיר נכון הן את צד הלקוח והן את צד השרת. לא מספיק לשנות רק צד אחד.
שלב 1: תצורה נכונה של השרת
שלושה כללי זהב בצד השרת
כלל 1 — הפעלת אישורים: כותרת התגובה של השרת חייבת לכלול את הערך הבא:
Access-Control-Allow-Credentials: true
כלל 2 — אין שימוש בתו כללי: כאשר אישורים מופעלים, אינכם יכולים להשתמש בתו הכללי * בכותרת Access-Control-Allow-Origin. עליכם לציין בדיוק את כתובת הדומיין המלאה של הצד הקדמי:
Access-Control-Allow-Origin: https://app.example.com
כלל 3 — תכונות העוגיה: יש להגדיר את העוגיה עם שתי תכונות: SameSite=None ו-Secure. ללא שתי תכונות אלו, הדפדפן יאחסן את העוגיה אך לעולם לא ישלח אותה בבקשות בין-דומיין.
קוד לדוגמה ב-Node.js (Express)
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: 'https://app.example.com', // דומיין מדויק של הצד הקדמי, ללא /
credentials: true
}));
app.post('/login', (req, res) => {
res.cookie('session_token', 'abc123', {
httpOnly: true, // מונע גישת JavaScript לעוגיה
secure: true, // נשלח רק דרך HTTPS
sameSite: 'none', // מאפשר שליחה בבקשות Cross-Origin
maxAge: 24 * 60 * 60 * 1000
});
res.json({ message: 'התחברות Successful' });
});
קוד לדוגמה ב-PHP
<?php
// ציינו את הדומיין המדויק של הצד הקדמי, לא *
header("Access-Control-Allow-Origin: https://app.example.com");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
// תגובה לבקשת Preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
// הגדרת העוגיה עם התכונות הנדרשות
setcookie('session_token', 'abc123', [
'expires' => time() + 86400,
'path' => '/',
'secure' => true, // חובה
'httponly' => true,
'samesite' => 'None' // חובה עבור Cross-Origin
]);
הערה: אם אתם משתמשים ב-Laravel, הגדירו את supports_credentials ל-true בקובץ config/cors.php והוסיפו את דומיין הצד הקדמי למערך allowed_origins.
שלב 2: תצורה נכונה של הלקוח (הצד הקדמי)
אפילו עם תצורה מלאה של השרת, הדפדפן עדיין לא ישלח עוגיות אלא אם תצהירו במפורש בצד הלקוח שבקשה זו היא "עם אישורים".
שימוש ב-Fetch API
fetch('https://api.example.com/user/profile', {
method: 'GET',
credentials: 'include' // שורה זו היא המפתח לפתרון הבעיה
})
.then(res => res.json())
.then(data => console.log(data));
שימוש ב-Axios
// עבור בקשה ספציפית
axios.get('https://api.example.com/user/profile', {
withCredentials: true
});
// או באופן גלובלי לכל הפרויקט
axios.defaults.withCredentials = true;
רשימת בדיקה לפתרון בעיות
אם הבעיה עדיין קיימת לאחר יישום האמור לעיל, בדקו את הפריטים הבאים לפי הסדר:
- ✅ האם שני הצדדים נמצאים ב-HTTPS? התכונה
Secureפירושה שהעוגיה עובדת רק על חיבורים מוצפנים. אם האתר שלכם נמצא ב-HTTP, הדפדפן לא יקבל את העוגיה. (חריג: סביבת פיתוח ב-localhost) - ✅ האם כתובת Origin מדויקת? כתובת
Access-Control-Allow-Originחייבת להתאים בדיוק לכתובת ה-URL שאתם רואים בדפדפן. אפילו הבדל ב-wwwאו קו נטוי סופי/יגרום לכשל. - ✅ האם בקשת OPTIONS מצליחה? בלשונית Network בכלי המפתחים של הדפדפן, בדקו את בקשת Preflight (עם שיטת OPTIONS). על בקשה זו להשיב עם קוד 200 או 204 וכותרת CORS נכונות.
- ✅ האם העוגיה נשמרה? בדפדפן, גשו ל-DevTools ← Application ← Cookies וודאו שהעוגיה נשמרה עם התכונות
Secureו-SameSite=None. - ✅ האם יש לכם Proxy או Firewall מתווך? לפעמים Cloudflare או שרתי אינטרנט כמו Nginx כותבים מחדש כותרות. בדקו גם את התצורה שלהם.
סיכום
שליחת עוגיות בבקשות בין-דומיין דורשת תיאום של שלושה גורמים: השרת עם Access-Control-Allow-Credentials: true ו-Origin מדויק, העוגיה עם תכונות SameSite=None; Secure, והלקוח עם הפעלה של credentials: 'include' או withCredentials: true. על ידי שמירה על שלוש נקודות אלו, הבעיה תיפתר לחלוטין.
תשתית אמינה, שקט נפשי למפתחים
יישום נכון של CORS וניהול עוגיות הוא רק חלק מהסיפור; התשתית שעליה הפרויקט שלכם רץ משחקת גם היא תפקיד מכריע ביציבות ובאבטחת השירות:
Radib Hosting — אירוח אתרים במהירות גבוהה עם תמיכה מלאה ב-SSL חינמי ותצורה סטנדרטית של כותרות; בחירה אידיאלית לאירוח הצד הקדמי והאחורי של הפרויקטים שלכם.
Radib Virtual Server — אם הפרויקט שלכם דורש גישה מלאה, משאבים ייעודיים וחופש בתצורת שרת האינטרנט (Nginx/Apache), שרתים וירטואליים של Radib עם חומרה חזקה ורשת יציבה הם הבחירה הטובה ביותר עבור API מקצועיים.
Radib Debugging and Security Services — אם אתם מתמודדים עם שגיאות CORS מורכבות, בעיות אימות או אתגרי אבטחה, צוות הטכני של Radib, עם ניסיון עמוק בפתרון בעיות ואבטחת יישומי אינטרנט, נמצא כאן כדי לעזור לכם לפתור את הבעיה מהשורש.


