مدتی بود که درصدی از پرداختها بر روی درگاههای پرداخت مشتریها با مشکل مواجه میشد و مبالغ پرداختی بدون مراجعه به وب سایت اصلی به حساب شخص برگشت میخورد ، وقتی با پشتیبانی درگاه پرداخت تماس گرفتم برعکس همیشه فوراً مشکل را تأیید و اظهار میکردند که مشکل از اونها هست و تشویق به اینکه از مشتریان بخواهیم از مرورگری به غیر از کروم استفاده کنند.
خوب این حرف اصلاً منطقی نبود و حتی من شک داشتم واقعاً مشکلی پیش اومده باشه چون مرحله پرداخت کامل میشد و مبلغ هم از حساب شخص کسر میشد ولی در اصطلاح بانکی Settle نمیشد و در واقع چون Verification سمت وب سایت ما انجام نمیشد پرداخت برگشت میخورد!
بعد از کلی بررسی سورسها و اطمینان از عملکرد صحیح وب سایت و در نهایت پایش Log ها متوجه شدم مرورگرهای کروم از یک نسخه خاص یعنی ۸۰ به بعد و اواخر بهمن ۹۸ با این مشکل روبرو شدهاند ، با بررسی Update های گوگل کروم متوجه شدم که در ماه فوریه گوگل در یکی از Update هاش چنانچه مقدار SameSite در Header های مربوط به کوکی تعیین نشده باشه به صورت پیشفرض بجای مقدار None از Lax استفاده میکنه و خوب وقتی ببینیم فرق این دو مقدار در پارامتر SameSite چیه متوجه مشکل میشویم.
به صورت پیشفرض توی همه مرورگرها مقدار SameSite برابر None هست یعنی اگه از سایتی خارج از دامنه ما درخواست Post یا Get به سایت ما ارسال بشود مرورگر کوکیهای مرتبط با دامنه و مسیر ما که SameSite برابر مقدار None دارند را ارسال میکنه.
حالا اگه مقدار SameSite برابر با Lax باشه این کوکیها برای درخواستهای Get ارسال میشه و برای درخواستهای مثلاً POST ارسال نمیشه . مشکل دقیقاً همینجاست چون توی خیلی از وب سایتها Authorization از طریق Session و همین کوکیها انجام میشه و درگاههای بانکی هم پس از پرداخت اطلاعات را به آدرس مورد نظر ما Post میکنن و در نتیجه Authorization انجام نمیشه و پرداخت کاربر هم به دلیل Verify و Settle نشدن برگشت میخوره!!!
اول از همه باید بگم که این کار گوگل در راستای افزایش امنیت بوده چون با مقدار دهی SameSite به Lax از حملات CSRF جلوگیری میشه و به نظرم بهتره حتی اگه به صورت مقطعی مشکل را حل میکنیم در بلند مدت نسبت به تصحیح عملکرد وب سایتمون اقدام کنیم.
برای اینکه مشکل را مقطعی حل کنیم میتونیم توی سرآیند یا همون Header مربوط به کوکی مقدار SameSite را برابر با None بگذاریم ولی باید توجه داشته باشیم کروم به شرطی قبول میکنه مقدار SameSite روی None باشه که سایت حتماً بر بستر SSL باشه و پارامتر Secure در Header کوکی تنظیم شده باشه که خوب با توجه به در دسترس بودن Let’s Encrypt میشه مشکل دوم را هم رایگان حل کرد.
اگه از Apache استفاده میکنید خیلی راحت توی htaccess. میشه نوشت:
Header always edit Set-Cookie (.*) "$1; secure; SameSite=None"
اگه از Nginx استفاده میکنید:
location / {
proxy_cookie_path / "/; secure; SameSite=None";
}
اگه میخواهیم توی Source خود PHP تغییر بدیم بر اساس نسخه PHP باید عمل کنیم اگه نسخه PHP کوچکتر از 7.3 هست:
setcookie('cookie-name', 'cookie-value', 0, '/; secure; SameSite=None');
اگه نسخه PHP برابر یا بزرگتر از 7.3 هست:
setcookie("cookie-name", "cookie-value", [
'expires' = 0,
'path' = '/',
'secure' = true,
'samesite' = 'None'
]);
توجه: کدهای بالا برای آشنایی با تغییر مورد نیاز هست و هیچ ضمانتی وجود نداره که عملاً در مورد وب سایت شما کار کنه!!!
ولی اگه قصد دارین امنیت سایتتون را فراهم کنین بهتره این مقدار را خودتون حتی برای مرورگرهای فایرفاکس و غیره بر روی Lax بگذارین تا حملات CSRF را مدیریت کنین و مقادیر برگشتی از درگاه پرداخت را توی مسیری که نیاز به Authorization و کوکیها نداره بررسی و پرداخت را تکمیل کنید و با یک Redirect ساده به صفحه اصلی سایت برگردین که بعد از این Redirect همه کوکیها در دسترس خواهند بود.