PHP का उपयोग करके क्रॉस-साइट अनुरोध जालसाजी (CSRF) टोकन को ठीक से कैसे जोड़ें


96

मैं अपनी वेबसाइट पर प्रपत्रों में कुछ सुरक्षा जोड़ने का प्रयास कर रहा हूं। रूपों में से एक AJAX का उपयोग करता है और दूसरा एक सीधा "हमसे संपर्क करें" फ़ॉर्म है। मैं एक सीएसआरएफ टोकन जोड़ने की कोशिश कर रहा हूं। मुझे जो समस्या हो रही है, वह यह है कि टोकन केवल HTML "मान" में ही दिखाई दे रहा है। बाकी समय, मान खाली है। यहां मैं AJAX फॉर्म पर कोड का उपयोग कर रहा हूं:

पीएचपी:

if (!isset($_SESSION)) {
    session_start();
$_SESSION['formStarted'] = true;
}
if (!isset($_SESSION['token']))
{$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;

}

एचटीएमएल

 <form>
//...
<input type="hidden" name="token" value="<?php echo $token; ?>" />
//...
</form>

कोई सुझाव?


बस जिज्ञासु, क्या के token_timeलिए प्रयोग किया जाता है?
झटके ४

@zerkms मैं वर्तमान में उपयोग नहीं कर रहा हूं token_time। मैं उस समय को सीमित करने जा रहा था जिसके भीतर एक टोकन वैध है, लेकिन अभी तक पूरी तरह से कोड को लागू नहीं किया है। स्पष्टता के लिए, मैंने इसे ऊपर के प्रश्न से हटा दिया है।
केन

1
@ पता: तो उपयोगकर्ता केस खोल सकता है जब उसने एक फॉर्म खोला है, इसे पोस्ट करें और अमान्य टोकन प्राप्त करें? (चूँकि इसे अमान्य कर दिया गया है)
झटके

@zerkms: धन्यवाद, लेकिन मैं थोड़ा भ्रमित हूं। कोई भी मौका आप मुझे एक उदाहरण प्रदान कर सकते हैं?
केन

2
@ पता: ज़रूर। मान लीजिए कि टोकन सुबह 10:00 बजे समाप्त हो रहा है। अब यह सुबह 09:59 बजे है। उपयोगकर्ता एक फॉर्म खोलता है और एक टोकन प्राप्त करता है (जो अभी भी मान्य है)। फिर उपयोगकर्ता 2 मिनट के लिए फॉर्म भरता है, और इसे भेजता है। जब तक यह सुबह 10:01 बजे तक है - टोकन को अमान्य माना जा रहा है, इस प्रकार उपयोगकर्ता को फ़ॉर्म त्रुटि मिलती है।
झटके

जवाबों:


290

सुरक्षा कोड के लिए, कृपया इस तरह से अपने टोकन उत्पन्न न करें: $token = md5(uniqid(rand(), TRUE));

इसे आज़माएं:

CSRF टोकन जनरेट करना

PHP 7

session_start();
if (empty($_SESSION['token'])) {
    $_SESSION['token'] = bin2hex(random_bytes(32));
}
$token = $_SESSION['token'];

सिडेनोट: मेरे नियोक्ता के ओपन सोर्स प्रोजेक्ट्स में से एक PHP 5 प्रोजेक्ट्स में बैकपोर्ट random_bytes()और एक पहल है random_int()। यह MIT लाइसेंस प्राप्त है और परागी / random_compat के रूप में Github और संगीतकार पर उपलब्ध है

PHP 5.3+ (या ext-mcrypt के साथ)

session_start();
if (empty($_SESSION['token'])) {
    if (function_exists('mcrypt_create_iv')) {
        $_SESSION['token'] = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
    } else {
        $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));
    }
}
$token = $_SESSION['token'];

CSRF टोकन का सत्यापन

सिर्फ उपयोग ==या यहां तक ​​कि ===, उपयोग न करें hash_equals()(PHP 5.6+ केवल, लेकिन हैश-कॉम्पिटिटर लाइब्रेरी के साथ पुराने संस्करणों के लिए उपलब्ध )।

if (!empty($_POST['token'])) {
    if (hash_equals($_SESSION['token'], $_POST['token'])) {
         // Proceed to process the form data
    } else {
         // Log this as a warning and keep an eye on these attempts
    }
}

पेर-फॉर्म टोकन के साथ आगे जाना

आप आगे टोकन का उपयोग करके केवल एक विशेष रूप के लिए उपलब्ध होने के लिए प्रतिबंधित कर सकते हैं hash_hmac()। HMAC एक विशेष प्रकार का हैश फ़ंक्शन है जो कमजोर हैश फ़ंक्शंस (जैसे MD5) के साथ भी उपयोग करने के लिए सुरक्षित है। हालांकि, मैं इसके बजाय हैश कार्यों के SHA-2 परिवार का उपयोग करने की सलाह देता हूं।

पहले, HMAC कुंजी के रूप में उपयोग के लिए एक दूसरा टोकन उत्पन्न करें, फिर इसे रेंडर करने के लिए इस तरह से तर्क का उपयोग करें:

<input type="hidden" name="token" value="<?php
    echo hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
?>" />

और फिर टोकन का सत्यापन करते समय एक सर्वांगसम ऑपरेशन का उपयोग करना:

$calc = hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
if (hash_equals($calc, $_POST['token'])) {
    // Continue...
}

एक रूप के लिए उत्पन्न टोकन को बिना जाने दूसरे संदर्भ में उपयोग नहीं किया जा सकता है $_SESSION['second_token']यह महत्वपूर्ण है कि आप एचएमएसी कुंजी के रूप में एक अलग टोकन का उपयोग करें, जो आप पृष्ठ पर छोड़ते हैं।

बोनस: हाइब्रिड दृष्टिकोण + टहनी एकीकरण

जो कोई भी Twig templating इंजन का उपयोग करता है, वह अपने Twig परिवेश में इस फ़िल्टर को जोड़कर एक सरल दोहरी रणनीति से लाभ उठा सकता है:

$twigEnv->addFunction(
    new \Twig_SimpleFunction(
        'form_token',
        function($lock_to = null) {
            if (empty($_SESSION['token'])) {
                $_SESSION['token'] = bin2hex(random_bytes(32));
            }
            if (empty($_SESSION['token2'])) {
                $_SESSION['token2'] = random_bytes(32);
            }
            if (empty($lock_to)) {
                return $_SESSION['token'];
            }
            return hash_hmac('sha256', $lock_to, $_SESSION['token2']);
        }
    )
);

इस ट्विग फ़ंक्शन के साथ, आप सामान्य प्रयोजन के टोकन दोनों का उपयोग कर सकते हैं जैसे:

<input type="hidden" name="token" value="{{ form_token() }}" />

या नीचे बंद संस्करण:

<input type="hidden" name="token" value="{{ form_token('/my_form.php') }}" />

टहनी केवल टेम्पलेट रेंडरिंग से संबंधित है; आपको अभी भी टोकन को ठीक से सत्यापित करना होगा। मेरी राय में, अधिकतम सुरक्षा की संभावना को बनाए रखते हुए, ट्विग रणनीति अधिक लचीलापन और सरलता प्रदान करती है।


एकल-उपयोग CSRF टोकन

यदि आपके पास सुरक्षा की आवश्यकता है, तो प्रत्येक CSRF टोकन को एक बार उपयोग करने योग्य बनाने की अनुमति है, सबसे सरल रणनीति प्रत्येक सफल सत्यापन के बाद इसे पुन: उत्पन्न करती है। हालाँकि, ऐसा करना हर पिछले टोकन को अमान्य कर देगा जो उन लोगों के साथ अच्छी तरह से मेल नहीं खाता है जो एक साथ कई टैब ब्राउज़ करते हैं।

पैरागॉन इनिशिएटिव एंटरप्राइजेज इन कोने के मामलों के लिए एक एंटी-सीएसआरएफ पुस्तकालय रखता है । यह विशेष रूप से प्रति-उपयोग टोकन के साथ काम करता है। जब सत्र डेटा (डिफ़ॉल्ट कॉन्फ़िगरेशन: 65535) में पर्याप्त टोकन संग्रहीत किए जाते हैं, तो यह सबसे पुराने अनरिड्ड टोकन को पहले बाहर कर देगा।


अच्छा है, लेकिन उपयोगकर्ता द्वारा फ़ॉर्म जमा करने के बाद $ टोकन कैसे बदलें? आपके मामले में, उपयोगकर्ता सत्र के लिए उपयोग किया जाने वाला एक टोकन।
अकाम

1
बारीकी से देखें कि कैसे github.com/paragonie/anti-csrf लागू किया गया है। टोकन एकल-उपयोग वाले हैं, लेकिन यह कई स्टोर करता है।
स्कॉट आर्किस्जेस्की

@ScottArciszewski सत्र आईडी से एक संदेश को गुप्त के साथ डाइजेस्ट करने के बारे में आप क्या सोचते हैं और फिर प्राप्त CSRF टोकन की तुलना करें फिर से सत्र आईडी से मेरे पिछले रहस्य के साथ हैशिंग? मुझे आशा है आप मेरा मतलब समझ गए।
MNR

1
मेरे पास CSRF टोकन को सत्यापित करने के बारे में एक प्रश्न है। अगर $ _POST ['टोकन'] खाली है, तो हमें आगे नहीं बढ़ना चाहिए, क्योंकि यह पोस्ट अनुरोध टोकन के बिना भेजा गया था, है ना?
हिरोकी

1
क्योंकि यह HTML रूप में प्रतिध्वनित होने वाला है, और आप चाहते हैं कि यह अप्रत्याशित हो, इसलिए हमलावर इसे केवल बना नहीं सकते। आप वास्तव में चुनौती-प्रतिक्रिया प्रमाणीकरण को यहां लागू कर रहे हैं, न कि केवल "हां यह रूप वैध है" क्योंकि एक हमलावर बस इसे खराब कर सकता है।
स्कॉट आर्किस्जेवस्की

24

सुरक्षा चेतावनी : md5(uniqid(rand(), TRUE))यादृच्छिक संख्या उत्पन्न करने का एक सुरक्षित तरीका नहीं है। अधिक जानकारी और एक समाधान के लिए यह उत्तर देखें जो क्रिप्टोग्राफिक रूप से सुरक्षित यादृच्छिक संख्या जनरेटर का लाभ उठाता है।

लगता है जैसे आपको अपने साथ और भी कुछ चाहिए।

if (!isset($_SESSION['token'])) {
    $token = md5(uniqid(rand(), TRUE));
    $_SESSION['token'] = $token;
    $_SESSION['token_time'] = time();
}
else
{
    $token = $_SESSION['token'];
}

11
नोट: मैं md5(uniqid(rand(), TRUE));सुरक्षा संदर्भों पर भरोसा नहीं करूंगा ।
स्कॉट आर्किसेवस्की

2

चर $tokenसत्र से पुनर्प्राप्त नहीं किया जा रहा है जब यह वहाँ है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.