flawopen.com/Type Juggling/PHP ==
क्या hashes की तुलना के लिए PHP == सुरक्षित है?
नहीं। == के साथ PHP दो संख्यात्मक strings की तुलना संख्यात्मक रूप से करता है, इसलिए वैज्ञानिक संकेतन वाली अलग strings PHP 8 में भी बराबर हो सकती हैं। पहले input का प्रकार जाँचें। सटीक मानों के लिए === और secret tokens या MAC के लिए hash_equals() उपयोग करें, ताकि सामग्री-निर्भर timing leakage न हो।
<?php // Both strings are numeric and represent zero $storedHash = "0e462097431906509019562988736854"; $submittedHash = "0e987654321"; // == returns true on PHP 7 and PHP 8 if ($storedHash == $submittedHash) { login(); } // Request data may also have the wrong type: $submitted = $_POST['token'] ?? null; if ($storedHash == $submitted) { login(); } // ?token[]=x supplies an array, not a string.
<?php
$submitted = $_POST['token'] ?? null;
if (!is_string($submitted)) {
http_response_code(400);
exit;
}
// For secret tokens or MACs:
$tokenIsValid = hash_equals($storedToken, $submitted);
if ($tokenIsValid) {
login();
}
// For non-secret identifiers, strict
// comparison checks both type and value:
$idsMatch = ($expectedId === $submitted);
// Passwords require password_verify(),
// not a hand-written hash comparison:
$passwordIsValid = password_verify($plain, $storedPasswordHash);
“Magic Hash” की समस्या
PHP 8 से पहले और बाद में दो संख्यात्मक strings की तुलना संख्यात्मक रूप से होती है। 0e से शुरू होकर केवल अंकों वाली hexadecimal hash वैध वैज्ञानिक-संकेतन string है जिसका मान शून्य है। उदाहरण के लिए, 0e462097431906509019562988736854 और 0e987654321 अलग strings हैं, पर दोनों शून्य दर्शाते हैं और == से बराबर हैं। PHP 8 ने string-to-number तुलना बदली, दो संख्यात्मक strings वाला यह मामला नहीं।
PHP 8 ने संख्या और गैर-संख्यात्मक string की तुलना बदली: अब string को शून्य मानने के बजाय उनके string रूपों की तुलना होती है। दो संख्यात्मक 0e… strings की क्लासिक तुलना नहीं बदली। किसी भी संस्करण में authentication के लिए == न उपयोग करें।
Request के प्रकार भी trust boundary हैं
Request पैरामीटर हमेशा strings नहीं होते। ?token[]=x जैसी query एक array बनाती है। इसे string API में देने से PHP संस्करण और फ़ंक्शन के अनुसार type error या अनपेक्षित code path हो सकता है। तुलना या hash_equals() से पहले request boundary पर string होना अनिवार्य करें।
मजबूत बचाव के दो हिस्से हैं: boundary पर input type जाँचें, फिर जरूरत के अनुसार तुलना चुनें। === type और value जाँचता है; hash_equals() secret strings की सामग्री-निर्भर timing leakage रोकता है।
अक्सर पूछे जाने वाले प्रश्न
नहीं। PHP 8 ने string-to-number तुलना बदली, लेकिन दो संख्यात्मक strings अब भी संख्यात्मक रूप से तुलना की जाती हैं। अलग 0e… strings बराबर हो सकती हैं। सटीक typed values के लिए ===, secrets के लिए hash_equals() और सभी समर्थित संस्करणों में type validation करें।
PHP hash_equals() को string सामग्री से जुड़े timing attacks के विरुद्ध सुरक्षित बताता है; सामान्य तुलना का समय अंतर के स्थान पर निर्भर कर सकता है। पहले ज्ञात secret और फिर user string दें। Password के लिए password_verify() उपयोग करें।
JavaScript के == में भी अप्रत्याशित परिणाम हो सकते हैं; इसलिए सामान्यतः === की सलाह दी जाती है। PHP का विशिष्ट Magic Hash मामला hexadecimal strings और वैज्ञानिक संकेतन की तुलना से पैदा होता है।