CSRF و راه‌های دفاع عملی (Cross-Site Request Forgery Defense) یکی از موضوعات پایه‌ای امنیت وب است که هر توسعه‌دهنده‌ای باید بر آن مسلط باشد؛ زیرا این حمله، برخلاف XSS، نیازی به تزریق کد ندارد و از اعتماد مرورگر به کوکی‌های کاربر سوءاستفاده می‌کند. در حمله‌ی CSRF (Cross-Site Request Forgery)، مهاجم کاربر را وادار می‌کند که یک درخواست ناخواسته به سایتی که در آن وارد شده است، ارسال کند. این درخواست، با کوکی‌های معتبر کاربر همراه می‌شود و سرور، آن را به‌عنوان یک درخواست قانونی می‌پذیرد. در این راهنما، مکانیزم این حمله و راه‌های دفاع عملی در برابر آن را به‌طور کامل بررسی می‌کنیم.

حمله‌ی CSRF، در فهرست ده آسیب‌پذیری برتر OWASP (Open Web Application Security Project) جایگاه ثابتی دارد و در بسیاری از سایت‌های وب، از جمله سایت‌های وردپرسی، به‌عنوان یک تهدید جدی شناخته می‌شود. برخلاف XSS که نیازمند تزریق کد است، CSRF از اعتماد سرور به کوکی‌های کاربر سوءاستفاده می‌کند و می‌تواند به انجام عملیات غیرمجاز مثل تغییر رمز عبور، انتقال وجه یا حذف داده منجر شود.

در این راهنما، ابتدا تعریف دقیق CSRF و تفاوت آن با XSS را بررسی می‌کنیم، سپس مکانیزم حمله را گام‌به‌گام باز می‌کنیم. در ادامه، راه‌های دفاع عملی شامل SameSite Cookie، CSRF Token، Double Submit Cookie، Origin Validation و Referer Validation را پوشش می‌دهیم. در بخش‌های بعدی به مباحث پیشرفته‌تر مثل CSRF در APIها، دفاع در وردپرس و اشتباهات رایج می‌پردازیم و در پایان با یک بخش پرسش‌های پرتکرار و یک فراخوان عملی، این مسیر را کامل می‌کنیم.

درک عمیق CSRF و راه‌های دفاع در برابر آن، فقط یک نیاز امنیتی نیست؛ یک ضرورت برای هر توسعه‌دهنده‌ای است که با فرم‌ها، APIها و سیستم‌های احراز هویت کار می‌کند. اگر این اصول را درست بیاموزید، می‌توانید از سایت و کاربران خود در برابر یکی از رایج‌ترین حملات وب محافظت کنید.

پیش از ورود به جزئیات، خلاصه‌ای از مسیر این راهنما را مرور کنیم: ابتدا تعریف CSRF و تفاوت آن با XSS را بررسی می‌کنیم. سپس مکانیزم حمله و سناریوهای واقعی را می‌بینیم. در ادامه، راه‌های دفاع عملی شامل SameSite Cookie، CSRF Token، Double Submit و Origin Validation را پوشش می‌دهیم. در بخش‌های بعدی به CSRF در APIها، دفاع در وردپرس و اشتباهات رایج می‌پردازیم و در پایان با پرسش‌های پرتکرار، این مسیر را کامل می‌کنیم.

نخستین برخورد جدی با CSRF، در یک پروژه‌ی فروشگاهی بود که فرم تغییر رمز عبور، هیچ توکن امنیتی نداشت. یک محقق امنیتی، با ساخت یک صفحه‌ی HTML ساده، توانست درخواست تغییر رمز را از طرف کاربر وارد‌شده ارسال کند. همین تجربه نشان داد که CSRF، برخلاف ظاهر ساده‌اش، می‌تواند به نفوذ کامل منجر شود. در ادامه، این مکانیزم را لایه‌به‌لایه باز می‌کنیم.

CSRF دقیقاً چیست؟

CSRF (Cross-Site Request Forgery) یک حمله‌ی امنیتی است که در آن، مهاجم کاربر را وادار می‌کند که یک درخواست ناخواسته به سایتی که در آن وارد شده است، ارسال کند. این درخواست، با کوکی‌های معتبر کاربر همراه می‌شود و سرور، آن را به‌عنوان یک درخواست قانونی می‌پذیرد. برخلاف XSS که کد مخرب را در مرورگر قربانی اجرا می‌کند، CSRF از اعتماد سرور به کوکی‌های کاربر سوءاستفاده می‌کند.

مفهوم Cross-Site Request Forgery در ویکی‌پدیا توضیح داده شده و درک آن برای هر توسعه‌دهنده‌ی وب ضروری است. این حمله، به‌دلیل اینکه نیازی به تزریق کد ندارد و از اعتماد مرورگر به کوکی‌ها سوءاستفاده می‌کند، یکی از ظریف‌ترین و خطرناک‌ترین حملات وب محسوب می‌شود.

در یک حمله‌ی CSRF، سه عنصر اصلی وجود دارد. عنصر اول، کاربر قربانی که در سایت هدف وارد شده و کوکی معتبر دارد. عنصر دوم، سایت هدف که به کوکی‌های کاربر اعتماد می‌کند. عنصر سوم، سایت مهاجم که درخواست مخرب را از مرورگر قربانی ارسال می‌کند.

<!-- صفحه مخرب در سایت مهاجم -->
<form action="https://bank.com/transfer" method="POST">
    <input type="hidden" name="to" value="attacker_account">
    <input type="hidden" name="amount" value="10000">
</form>
<script>document.forms[0].submit();</script>

در این مثال، وقتی کاربر وارد‌شده به سایت بانک، صفحه‌ی مخرب را باز می‌کند، فرم به‌طور خودکار ارسال می‌شود و درخواست انتقال وجه، با کوکی معتبر کاربر به سرور بانک ارسال می‌شود. سرور بانک، این درخواست را به‌عنوان یک درخواست قانونی می‌پذیرد و انتقال انجام می‌شود.

برای مطالعه‌ی عمیق‌تر این نوع حمله، مقاله CSRF چیست و چگونه دفع می‌شود؟ را مطالعه کنید. همچنین مقاله امنیت وب چیست و چه اصولی دارد؟ مفاهیم پایه‌ای را پوشش می‌دهد.

CSRF از اعتماد سرور به کوکی‌های کاربر سوءاستفاده می‌کند. سرور، کوکی معتبر را می‌بیند و فرض می‌کند که درخواست از طرف کاربر واقعی است، در حالی که ممکن است از طرف یک سایت مخرب باشد.

تفاوت CSRF و XSS

CSRF و XSS دو حمله‌ی متفاوت هستند که گاهی با هم اشتباه گرفته می‌شوند. درک تفاوت آن‌ها، برای انتخاب استراتژی دفاعی مناسب ضروری است.

معیارCSRFXSS
نقطه حملهاعتماد سرور به کوکیاعتماد مرورگر به کد صفحه
نیاز به تزریق کدخیربله
هدف اصلیانجام عملیات غیرمجازسرقت داده و جعل هویت
نیاز به تعامل کاربربله (کلیک یا بازدید)بله (اجرای کد)
دفاع اصلیCSRF Token و SameSiteپاک‌سازی و فرار دادن

در CSRF، مهاجم کد مخربی را در سایت قربانی اجرا نمی‌کند. در عوض، از مرورگر قربانی برای ارسال یک درخواست معتبر به سایت قربانی استفاده می‌کند. این درخواست، با کوکی‌های معتبر کاربر همراه است و سرور، آن را می‌پذیرد.

در XSS، مهاجم کد مخربی را در صفحه‌ی سایت قربانی تزریق می‌کند و مرورگر قربانی، آن را اجرا می‌کند. این کد، می‌تواند به کوکی‌ها، LocalStorage و DOM دسترسی داشته باشد و داده‌های حساس را به‌سرقت ببرد.

نکته‌ی مهم در مورد تفاوت این دو حمله این است که XSS می‌تواند برای دور زدن دفاع‌های CSRF استفاده شود. اگر سایت شما در برابر XSS آسیب‌پذیر باشد، مهاجم می‌تواند با استفاده از XSS، توکن CSRF را بخواند و از آن برای ارسال درخواست معتبر استفاده کند.

برای مطالعه‌ی عمیق‌تر درباره‌ی XSS، مقاله حملات XSS چیست و چگونه جلوگیری کنیم؟ را مطالعه کنید. همچنین مقاله حملات SQL Injection و راه‌های مقابله نکات تکمیلی دارد.

مکانیزم حمله CSRF

مکانیزم حمله‌ی CSRF، بر پایه‌ی اعتماد سرور به کوکی‌های کاربر است. در این حمله، مهاجم از چند روش برای ارسال درخواست از مرورگر قربانی استفاده می‌کند.

روش اول، فرم مخفی. مهاجم یک فرم مخفی در سایت خود قرار می‌دهد که به‌طور خودکار ارسال می‌شود. این فرم، به آدرس سایت هدف اشاره می‌کند و درخواست را با کوکی‌های کاربر ارسال می‌کند.

<form action="https://example.com/change-password" method="POST" id="csrf">
    <input type="hidden" name="new_password" value="hacked123">
</form>
<script>document.getElementById('csrf').submit();</script>

روش دوم، تصویر مخفی. مهاجم یک تصویر با آدرس سایت هدف قرار می‌دهد. وقتی مرورگر تلاش می‌کند تصویر را بارگذاری کند، درخواست GET به سایت هدف ارسال می‌شود. این روش، فقط برای درخواست‌های GET کار می‌کند.

<img src="https://example.com/delete-account?confirm=1" width="0" height="0">

روش سوم، iframe مخفی. مهاجم یک iframe مخفی در سایت خود قرار می‌دهد که به سایت هدف اشاره می‌کند. درخواست‌های ارسالی از iframe، با کوکی‌های کاربر همراه می‌شوند.

<iframe src="https://example.com/action" style="display:none"></iframe>

روش چهارم، XHR یا Fetch. اگرچه مرورگرهای مدرن، درخواست‌های Cross-Origin را محدود می‌کنند، اما در برخی سناریوها، مهاجم می‌تواند از XHR یا Fetch برای ارسال درخواست استفاده کند. این روش، معمولاً نیازمند CORS نامناسب در سایت هدف است.

fetch('https://example.com/action', {
    method: 'POST',
    credentials: 'include',
    body: new FormData(document.getElementById('csrf'))
});

نکته‌ی مهم در مورد مکانیزم CSRF این است که این حمله، به‌دلیل اینکه از کوکی‌های معتبر کاربر استفاده می‌کند، توسط بسیاری از سیستم‌های تشخیص نفوذ نادیده گرفته می‌شود. به همین دلیل، دفاع در برابر CSRF باید در سطح اپلیکیشن پیاده‌سازی شود.

سناریوهای واقعی حمله

CSRF در سناریوهای مختلفی می‌تواند رخ دهد. در این بخش، چند سناریوی واقعی را بررسی می‌کنیم.

سناریوی اول، تغییر رمز عبور. مهاجم کاربر را وادار می‌کند که یک فرم تغییر رمز عبور را ارسال کند. اگر سایت در برابر CSRF محافظت نشده باشد، رمز عبور تغییر می‌کند و مهاجم می‌تواند با رمز جدید وارد شود.

<!-- صفحه مخرب -->
<form action="https://example.com/profile/change-password" method="POST">
    <input type="hidden" name="new_password" value="attacker_password">
    <input type="hidden" name="confirm_password" value="attacker_password">
</form>
<script>document.forms[0].submit();</script>

سناریوی دوم، انتقال وجه. در سایت‌های بانکی یا پرداخت، مهاجم می‌تواند کاربر را وادار به انتقال وجه به حساب خود کند. این سناریو، به‌دلیل پیامدهای مالی، بسیار خطرناک است.

سناریوی سوم، حذف حساب. مهاجم کاربر را وادار می‌کند که حساب خود را حذف کند. این سناریو، اگرچه پیامد مالی ندارد، اما می‌تواند به از دست رفتن داده منجر شود.

سناریوی چهارم، تغییر ایمیل. مهاجم ایمیل کاربر را تغییر می‌دهد و سپس با استفاده از قابلیت بازیابی رمز عبور، کنترل کامل حساب را به‌دست می‌گیرد. این سناریو، یکی از خطرناک‌ترین سناریوهای CSRF است.

<form action="https://example.com/profile/change-email" method="POST">
    <input type="hidden" name="email" value="attacker@evil.com">
</form>
<script>document.forms[0].submit();</script>

سناریوی پنجم، ارسال پست. در سایت‌های محتوایی، مهاجم می‌تواند کاربر را وادار به ارسال یک پست یا نظر کند. این سناریو، اگرچه پیامد امنیتی ندارد، اما می‌تواند برای اسپم استفاده شود.

نکته‌ی مهم در مورد این سناریوها این است که همه‌ی آن‌ها نیازمند یک شرط هستند: کاربر باید در سایت هدف وارد شده باشد. اگر کاربر وارد نشده باشد، کوکی معتبری وجود ندارد و حمله موفق نمی‌شود.

برای مطالعه‌ی عمیق‌تر درباره‌ی حملات رایج، مقاله اشتباهات امنیتی رایج در وب را مطالعه کنید.

CSRF فقط در صورتی موفق می‌شود که کاربر در سایت هدف وارد شده باشد. اگر کاربر وارد نشده باشد، کوکی معتبری وجود ندارد و حمله شکست می‌خورد.

SameSite Cookie و نقش آن

SameSite یک ویژگی کوکی است که به مرورگر می‌گوید که آیا کوکی باید در درخواست‌های Cross-Site ارسال شود یا نه. این ویژگی، یکی از قوی‌ترین دفاع‌ها در برابر CSRF است و در مرورگرهای مدرن، به‌طور پیش‌فرض فعال است.

SameSite سه مقدار می‌تواند داشته باشد. مقدار Strict. کوکی فقط در درخواست‌های Same-Site ارسال می‌شود. این مقدار، قوی‌ترین دفاع در برابر CSRF است، اما می‌تواند تجربه کاربری را در برخی سناریوها خراب کند. مقدار Lax. کوکی در درخواست‌های Same-Site و در ناوبری‌های Top-Level Cross-Site با متد GET ارسال می‌شود. این مقدار، تعادل خوبی بین امنیت و تجربه کاربری برقرار می‌کند. مقدار None. کوکی در همه‌ی درخواست‌ها ارسال می‌شود. این مقدار، هیچ دفاعی در برابر CSRF فراهم نمی‌کند و فقط در سناریوهای خاص (مثل Embed) استفاده می‌شود.

Set-Cookie: session_id=abc123; SameSite=Lax; Secure; HttpOnly

نکته‌ی مهم در مورد SameSite این است که این ویژگی، در مرورگرهای قدیمی پشتیبانی نمی‌شود. بنابراین، باید به‌عنوان یک لایه‌ی اضافی استفاده شود، نه به‌عنوان جایگزین برای CSRF Token.

در PHP، می‌توانید SameSite را در تنظیمات کوکی تعیین کنید.

setcookie('session_id', $session_id, [
    'samesite' => 'Lax',
    'secure' => true,
    'httponly' => true,
    'expires' => time() + 3600,
]);

در وردپرس، می‌توانید از فیلتر auth_cookie_options برای تنظیم SameSite استفاده کنید.

add_filter('auth_cookie_options', function($options) {
    $options['samesite'] = 'Lax';
    return $options;
});

برای مطالعه‌ی عمیق‌تر درباره‌ی امنیت کوکی‌ها، مقاله چگونه نشست‌های کاربری را امن کنیم؟ را مطالعه کنید.

CSRF Token و Synchronizer Pattern

CSRF Token یکی از رایج‌ترین و مؤثرترین روش‌های دفاع در برابر CSRF است. در این روش، سرور یک توکن تصادفی تولید می‌کند و آن را در فرم قرار می‌دهد. وقتی فرم ارسال می‌شود، سرور توکن را بررسی می‌کند و اگر معتبر نباشد، درخواست را رد می‌کند.

الگوی Synchronizer Token Pattern، یک الگوی استاندارد برای پیاده‌سازی CSRF Token است. در این الگو، توکن در نشست کاربر ذخیره می‌شود و در هر فرم قرار می‌گیرد. وقتی فرم ارسال می‌شود، سرور توکن فرم را با توکن نشست مقایسه می‌کند.

// تولید توکن
function generate_csrf_token() {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

// قرار دادن توکن در فرم
<input type="hidden" name="csrf_token" value="<?php echo generate_csrf_token(); ?>">

// بررسی توکن
function verify_csrf_token($token) {
    if (empty($_SESSION['csrf_token'])) {
        return false;
    }
    return hash_equals($_SESSION['csrf_token'], $token);
}

نکته‌ی مهم در پیاده‌سازی CSRF Token، استفاده از hash_equals() برای مقایسه است. این تابع، در برابر حملات Timing Attack مقاوم است. استفاده از === یا == برای مقایسه توکن، می‌تواند به Timing Attack منجر شود.

نکته‌ی ظریف دیگر، تجدید توکن پس از ورود موفق است. اگر توکن قبل از ورود تولید شده باشد و پس از ورود تجدید نشود، ممکن است در معرض Session Fixation قرار گیرد.

// تجدید توکن پس از ورود
session_regenerate_id(true);
unset($_SESSION['csrf_token']);

در وردپرس، توابع wp_nonce_field()، wp_nonce_url() و wp_verify_nonce() برای پیاده‌سازی CSRF Token استفاده می‌شوند. این توابع، یک توکن با عمر محدود تولید می‌کنند و آن را با نشست کاربر و یک رشته‌ی مشخص گره می‌زنند.

// قرار دادن nonce در فرم
wp_nonce_field('my_action', 'my_nonce');

// بررسی nonce
if (!isset($_POST['my_nonce']) ||
    !wp_verify_nonce($_POST['my_nonce'], 'my_action')) {
    wp_die('درخواست نامعتبر');
}

برای مطالعه‌ی عمیق‌تر درباره‌ی نانس در وردپرس، مقاله نانس وردپرس چیست و چگونه امنیت فرم و درخواست AJAX را تقویت کنیم؟ را مطالعه کنید. همچنین مقاله چگونه نانس را در فرم‌های سفارشی وردپرس درست پیاده‌سازی کنیم؟ نکات عملی بیشتری دارد.

Double Submit Cookie

الگوی Double Submit Cookie، یک روش دفاع در برابر CSRF است که در آن، توکن هم در کوکی و هم در پارامتر درخواست قرار می‌گیرد. سرور، این دو مقدار را مقایسه می‌کند و اگر یکسان باشند، درخواست را می‌پذیرد. این روش، به‌دلیل اینکه نیازی به ذخیره‌سازی توکن در سرور ندارد، برای سیستم‌های توزیع‌شده و Stateless مناسب است.

// تولید توکن و قرار دادن در کوکی
$token = bin2hex(random_bytes(32));
setcookie('csrf_token', $token, [
    'samesite' => 'Strict',
    'secure' => true,
]);

// قرار دادن توکن در فرم
<input type="hidden" name="csrf_token" value="<?php echo $token; ?>">

// بررسی توکن
function verify_double_submit($cookie_token, $form_token) {
    return hash_equals($cookie_token, $form_token);
}

نکته‌ی مهم در Double Submit Cookie این است که کوکی باید با پرچم SameSite تنظیم شود تا در درخواست‌های Cross-Site ارسال نشود. اگر کوکی با SameSite=None تنظیم شود، مهاجم می‌تواند توکن را بخواند و از آن استفاده کند.

نکته‌ی ظریف دیگر، استفاده از یک توکن تصادفی است که قابل پیش‌بینی نباشد. توکن باید با random_bytes() یا مشابه تولید شود، نه با rand() یا mt_rand().

مزیت اصلی Double Submit Cookie، عدم نیاز به ذخیره‌سازی توکن در سرور است. این ویژگی، آن را برای سیستم‌های توزیع‌شده و Microservices مناسب می‌کند. عیب اصلی آن، وابستگی به کوکی است؛ اگر مرورگر از کوکی پشتیبانی نکند یا کوکی مسدود شده باشد، این روش کار نمی‌کند.

Origin و Referer Validation

Origin و Referer Validation، دو روش دفاع در برابر CSRF هستند که بر پایه‌ی بررسی منبع درخواست کار می‌کنند. در این روش‌ها، سرور بررسی می‌کند که درخواست از دامنه‌ی مجاز آمده است یا نه.

Origin Header. این هدر، توسط مرورگر در درخواست‌های Cross-Origin ارسال می‌شود و دامنه‌ی مبدأ را مشخص می‌کند. این هدر، قابل جعل نیست و یک روش قابل اعتماد برای بررسی منبع است.

// بررسی Origin
function verify_origin() {
    $origin = $_SERVER['HTTP_ORIGIN'] ?? '';
    $allowed = ['https://example.com', 'https://www.example.com'];
    return in_array($origin, $allowed, true);
}

Referer Header. این هدر، آدرس کامل صفحه‌ای که درخواست از آن ارسال شده را مشخص می‌کند. این هدر، ممکن است توسط برخی تنظیمات حریم خصوصی حذف شود و بنابراین، قابل اعتماد نیست.

// بررسی Referer
function verify_referer() {
    $referer = $_SERVER['HTTP_REFERER'] ?? '';
    if (empty($referer)) {
        return false;
    }
    $parsed = parse_url($referer);
    return isset($parsed['host']) &&
           in_array($parsed['host'], ['example.com', 'www.example.com'], true);
}

نکته‌ی مهم در مورد Origin و Referer Validation این است که این روش‌ها، به‌تنهایی کافی نیستند. برخی مرورگرها یا تنظیمات حریم خصوصی، ممکن است این هدرها را حذف کنند. بنابراین، باید به‌عنوان یک لایه‌ی اضافی استفاده شوند.

نکته‌ی ظریف دیگر، بررسی هر دو هدر است. اگر Origin وجود دارد، از آن استفاده کنید. اگر Origin وجود ندارد، از Referer استفاده کنید. اگر هیچ‌کدام وجود ندارد، درخواست را رد کنید.

function verify_request_source() {
    if (!empty($_SERVER['HTTP_ORIGIN'])) {
        return verify_origin($_SERVER['HTTP_ORIGIN']);
    }
    if (!empty($_SERVER['HTTP_REFERER'])) {
        return verify_referer($_SERVER['HTTP_REFERER']);
    }
    return false;
}

برای مطالعه‌ی عمیق‌تر درباره‌ی هدرهای امنیتی، مقاله هدرهای امنیتی HTTP (Security Headers) چه کاربردی دارند؟ را مطالعه کنید.

Custom Headers و JSON APIها

در APIهای JSON، استفاده از CSRF Token می‌تواند چالش‌برانگیز باشد، زیرا فرم‌های HTML در این APIها وجود ندارند. یک راه‌حل رایج، استفاده از Custom Header است. در این روش، API انتظار دارد که درخواست‌ها یک هدر سفارشی مثل X-Requested-With یا X-CSRF-Token داشته باشند.

// درخواست از سمت کلاینت
fetch('/api/action', {
    method: 'POST',
    headers: {
        'X-CSRF-Token': getCsrfToken(),
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
});

// بررسی در سمت سرور
function verify_api_csrf() {
    $token = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
    if (!verify_csrf_token($token)) {
        http_response_code(403);
        exit('CSRF token invalid');
    }
}

مزیت اصلی Custom Header، سادگی پیاده‌سازی و سازگاری با APIهای JSON است. عیب اصلی آن، نیازمند تنظیم CORS مناسب است؛ اگر CORS به‌درستی تنظیم نشود، درخواست‌های Cross-Origin ممکن است مسدود شوند.

نکته‌ی مهم در مورد Custom Header این است که مرورگر، به‌طور پیش‌فرض اجازه نمی‌دهد که هدرهای سفارشی در درخواست‌های Cross-Origin ارسال شوند، مگر اینکه سرور با CORS موافقت کند. این ویژگی، یک لایه‌ی دفاعی طبیعی در برابر CSRF فراهم می‌کند.

// تنظیم CORS
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Headers: Content-Type, X-CSRF-Token
Access-Control-Allow-Credentials: true

برای مطالعه‌ی عمیق‌تر درباره‌ی امنیت API، مقاله امنیت API در وب چگونه تامین می‌شود؟ راهنمای Security عملی را مطالعه کنید. همچنین مقاله امنیت API در وب نکات تکمیلی دارد.

دفاع در برابر CSRF در وردپرس

وردپرس، مجموعه‌ای از توابع و مکانیزم‌ها برای دفاع در برابر CSRF فراهم کرده است. اصلی‌ترین مکانیزم، Nonce است که یک توکن با عمر محدود است و با نشست کاربر و یک رشته‌ی مشخص گره می‌خورد.

// در فرم
<form method="post">
    <?php wp_nonce_field('my_action', 'my_nonce'); ?>
    <input type="text" name="data">
    <button type="submit">ارسال</button>
</form>

// در پردازش
if (!isset($_POST['my_nonce']) ||
    !wp_verify_nonce($_POST['my_nonce'], 'my_action')) {
    wp_die('درخواست نامعتبر');
}

علاوه بر Nonce، وردپرس از SameSite Cookie نیز پشتیبانی می‌کند. در نسخه‌های اخیر، کوکی‌های نشست به‌طور پیش‌فرض با SameSite=Lax تنظیم می‌شوند.

add_filter('auth_cookie_options', function($options) {
    $options['samesite'] = 'Lax';
    return $options;
});

نکته‌ی مهم در دفاع در برابر CSRF در وردپرس، استفاده از Nonce در همه‌ی فرم‌ها و درخواست‌های AJAX است. بدون Nonce، فرم‌ها و درخواست‌های AJAX در برابر CSRF آسیب‌پذیر هستند.

// ارسال درخواست AJAX
jQuery.post(ajaxurl, {
    action: 'my_action',
    data: 'value',
    _ajax_nonce: '<?php echo wp_create_nonce('my_ajax_action'); ?>'
}, function(response) {
    console.log(response);
});

// پردازش درخواست AJAX
add_action('wp_ajax_my_action', function() {
    check_ajax_referer('my_ajax_action', '_ajax_nonce');
    // پردازش
});

برای مطالعه‌ی عمیق‌تر درباره‌ی امنیت وردپرس، مقاله هوک‌های وردپرس و افزایش امنیت کد را مطالعه کنید. همچنین مقاله چگونه سایت وردپرسی را در برابر هک محافظت کنیم؟ نکات عملی بیشتری دارد.

در وردپرس، همیشه از Nonce در فرم‌ها و درخواست‌های AJAX استفاده کنید. Nonce، یک لایه‌ی دفاعی قوی در برابر CSRF است که به‌طور بومی در وردپرس پشتیبانی می‌شود.

CSRF در REST API و GraphQL

در APIهای REST و GraphQL، دفاع در برابر CSRF چالش‌های خاص خود را دارد. اگر API شما از کوکی برای احراز هویت استفاده می‌کند، در برابر CSRF آسیب‌پذیر است. اگر از توکن (مثل JWT) در هدر Authorization استفاده می‌کند، در برابر CSRF مقاوم است، زیرا مرورگر به‌طور خودکار این هدر را ارسال نمی‌کند.

// API آسیب‌پذیر در برابر CSRF (استفاده از کوکی)
fetch('/api/transfer', {
    method: 'POST',
    credentials: 'include',
    body: JSON.stringify({to: 'attacker', amount: 10000})
});

// API مقاوم در برابر CSRF (استفاده از توکن در هدر)
fetch('/api/transfer', {
    method: 'POST',
    headers: {
        'Authorization': 'Bearer ' + token
    },
    body: JSON.stringify({to: 'attacker', amount: 10000})
});

نکته‌ی مهم در مورد APIها این است که اگر از کوکی برای احراز هویت استفاده می‌کنید، باید CSRF Token یا SameSite Cookie را پیاده‌سازی کنید. اگر از توکن در هدر استفاده می‌کنید، در برابر CSRF مقاوم هستید، زیرا مهاجم نمی‌تواند هدر را از طرف کاربر ارسال کند.

نکته‌ی ظریف دیگر، تنظیم CORS مناسب است. اگر CORS به‌درستی تنظیم نشود، ممکن است درخواست‌های Cross-Origin مسدود شوند یا به‌طور ناخواسته، دسترسی‌های اضافی داده شود.

Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true

برای مطالعه‌ی عمیق‌تر درباره‌ی API و GraphQL، مقاله GraphQL یا REST؟ راهنمای انتخاب برای پروژه‌های واقعی را مطالعه کنید.

اشتباهات رایج در دفاع در برابر CSRF

در بازبینی پروژه‌های مختلف، اشتباهات تکراری در دفاع در برابر CSRF دیده می‌شود که هر کدام می‌تواند به کاهش امنیت منجر شود.

اشتباه اول، تکیه بر یک لایه‌ی دفاعی. CSRF یک حمله‌ی چندلایه است و دفاع در برابر آن نیز باید چندلایه باشد. تکیه بر یک لایه، مثل CSRF Token تنها، کافی نیست.

اشتباه دوم، عدم تجدید توکن. اگر توکن CSRF پس از ورود موفق تجدید نشود، ممکن است در معرض Session Fixation قرار گیرد.

اشتباه سوم، استفاده از توکن‌های قابل پیش‌بینی. توکن CSRF باید تصادفی و غیرقابل پیش‌بینی باشد. استفاده از rand() یا mt_rand() به‌جای random_bytes()، امنیت را کاهش می‌دهد.

اشتباه چهارم، عدم بررسی Origin. Origin Header یک لایه‌ی دفاعی قوی است که بسیاری از پروژه‌ها آن را نادیده می‌گیرند.

اشتباه پنجم، تنظیم SameSite=None. اگر کوکی با SameSite=None تنظیم شود، هیچ دفاعی در برابر CSRF فراهم نمی‌کند.

اشتباه ششم، عدم استفاده از Nonce در وردپرس. در وردپرس، فرم‌ها و درخواست‌های AJAX بدون Nonce، در برابر CSRF آسیب‌پذیر هستند.

اشتباه هفتم، عدم تست سناریوهای حمله. بدون تست، نمی‌دانید که آیا سایت شما در برابر CSRF آسیب‌پذیر است یا نه.

اشتباه هشتم، استفاده از GET برای عملیات حساس. عملیات حساس باید با POST انجام شوند، نه با GET. درخواست‌های GET می‌توانند به‌راحتی از طریق تصویر یا لینک ارسال شوند.

// نادرست: عملیات حساس با GET
<a href="/delete-account?confirm=1">حذف حساب</a>

// درست: عملیات حساس با POST
<form method="post" action="/delete-account">
    <?php wp_nonce_field('delete_account'); ?>
    <button type="submit">حذف حساب</button>
</form>

برای مطالعه‌ی عمیق‌تر درباره‌ی اشتباهات رایج، مقاله اشتباهات امنیتی رایج در وب را مطالعه کنید.

پرسش‌های پرتکرار درباره CSRF

CSRF چیست و چگونه کار می‌کند؟ CSRF یک حمله است که در آن، مهاجم کاربر را وادار می‌کند که یک درخواست ناخواسته به سایتی که در آن وارد شده است، ارسال کند. این درخواست، با کوکی‌های معتبر کاربر همراه می‌شود و سرور، آن را به‌عنوان یک درخواست قانونی می‌پذیرد.

تفاوت CSRF و XSS چیست؟ XSS کد مخرب را در مرورگر قربانی اجرا می‌کند، در حالی که CSRF کاربر را وادار به انجام یک عمل ناخواسته می‌کند. XSS می‌تواند برای CSRF استفاده شود، اما این دو حمله‌ی متفاوتی هستند.

بهترین راه دفاع در برابر CSRF چیست؟ بهترین راه، ترکیب چند لایه‌ی دفاعی است: CSRF Token، SameSite Cookie، Origin Validation و Custom Header. هیچ لایه‌ی واحدی، صد درصد مؤثر نیست.

آیا SameSite Cookie برای جلوگیری از CSRF کافی است؟ SameSite Cookie یک لایه‌ی دفاعی قوی است، اما به‌تنهایی کافی نیست. باید همراه با CSRF Token و سایر لایه‌ها استفاده شود.

چگونه CSRF Token را پیاده‌سازی کنم؟ یک توکن تصادفی تولید کنید، آن را در نشست کاربر ذخیره کنید، در فرم قرار دهید و هنگام ارسال فرم، آن را بررسی کنید. از hash_equals() برای مقایسه استفاده کنید.

آیا CSRF در APIها هم رخ می‌دهد؟ بله، اگر API شما از کوکی برای احراز هویت استفاده کند، در برابر CSRF آسیب‌پذیر است. اگر از توکن در هدر Authorization استفاده کند، در برابر CSRF مقاوم است.

چگونه CSRF را در وردپرس دفع کنم؟ از توابع wp_nonce_field()، wp_nonce_url() و wp_verify_nonce() استفاده کنید. همچنین SameSite Cookie را فعال کنید.

آیا CSRF می‌تواند به نفوذ کامل منجر شود؟ بله، CSRF می‌تواند به تغییر رمز عبور، تغییر ایمیل، انتقال وجه و حتی حذف حساب منجر شود. در سایت‌های با دسترسی بالا، این می‌تواند به نفوذ کامل منجر شود.

آیا GET در برابر CSRF آسیب‌پذیر است؟ بله، درخواست‌های GET می‌توانند از طریق تصویر یا لینک ارسال شوند و در برابر CSRF آسیب‌پذیر باشند. عملیات حساس باید با POST انجام شوند.

چگونه CSRF را تست کنم؟ یک صفحه‌ی HTML با فرم مخفی بسازید که به سایت هدف ارسال می‌شود. اگر درخواست پذیرفته شد، سایت در برابر CSRF آسیب‌پذیر است.

آیا CSRF Token باید در هر درخواست تجدید شود؟ خیر، توکن می‌تواند برای چند درخواست معتبر باشد. اما پس از ورود موفق، باید تجدید شود تا از Session Fixation جلوگیری شود.

آیا Double Submit Cookie امن است؟ Double Submit Cookie امن است، به شرطی که کوکی با SameSite تنظیم شود و توکن تصادفی باشد. اگر کوکی با SameSite=None تنظیم شود، مهاجم می‌تواند توکن را بخواند.

آیا Origin Validation کافی است؟ Origin Validation یک لایه‌ی دفاعی قوی است، اما به‌تنهایی کافی نیست. برخی مرورگرها یا تنظیمات حریم خصوصی، ممکن است Origin را حذف کنند.

آیا CSRF در اپلیکیشن‌های موبایل رخ می‌دهد؟ بله، اگر اپلیکیشن موبایل از WebView برای نمایش محتوای وب استفاده کند، ممکن است در برابر CSRF آسیب‌پذیر باشد.

CSRF یکی از رایج‌ترین و خطرناک‌ترین آسیب‌پذیری‌های وب است که می‌تواند به انجام عملیات غیرمجاز، تغییر داده و حتی نفوذ کامل منجر شود. دفاع در برابر آن، نیازمند یک استراتژی چندلایه است که شامل CSRF Token، SameSite Cookie، Origin Validation و Custom Header می‌شود. اگر این اصول را در پروژه‌های خود رعایت کنید، می‌توانید سایت خود را در برابر این حمله مقاوم کنید.

اگر در پروژه‌ای واقعی با چالشی در دفاع در برابر CSRF برخورد کرده‌اید — مثلاً یک مورد خاص از تداخل CSRF Token با کش، یک سناریوی پیچیده در APIهای Stateless، یا تجربه‌ای از کشف یک آسیب‌پذیری در فرم‌های سفارشی — برایتان جالب است بدانید که این تجربه‌ها می‌توانند به خواننده‌ی بعدی کمک کنند. به‌خصوص اگر راه‌حل خلاقانه‌ای برای یک مسئله‌ی امنیتی پیدا کرده‌اید. تجربه‌ی خودتان را در دیدگاه‌ها بنویسید؛ چه درباره‌ی روش‌های دفاعی، چه درباره‌ی ابزارهای تست، و چه درباره‌ی اشتباهاتی که در مسیر یادگیری مرتکب شده‌اید و درس ارزشمندی از آن‌ها گرفته‌اید.