Kodokon kodokon.com

वेब सुरक्षा: XSS, CSRF और इंजेक्शन

XSS, CSRF और SQL इंजेक्शन को गहराई से समझें ताकि यह ठीक-ठीक पता चले कि htmlspecialchars, टोकन और प्रिपेयर्ड स्टेटमेंट असल में क्या रोकते हैं।

12 मिनट · 3 प्रश्न

इस पाठ को Kodokon में खोलें

वेब की तीन बड़ी भेद्यता श्रेणियाँ - XSS, CSRF और इंजेक्शन - सभी का मूल कारण एक ही है: उपयोगकर्ता द्वारा दिया गया डेटा अंततः कोड (HTML, SQL या एक वैध अनुरोध) के रूप में व्याख्यायित हो जाता है। XSS से शुरू करते हैं: यदि आप $_GET से कोई वैल्यू बिना एस्केप किए प्रदर्शित करते हैं, तो एक हमलावर <script> टैग इंजेक्ट कर सकता है और आपके अन्य आगंतुकों के ब्राउज़र में JavaScript चला सकता है - सेशन चुराते हुए, उनकी जानकारी के बिना कार्रवाई करते हुए। ?comment=<script>alert(1)</script> के साथ, नीचे दिया गया पहला आउटपुट स्क्रिप्ट को चलाता है; दूसरा उसे निष्क्रिय कर देता है। यहाँ दो फ़्लैग महत्वपूर्ण हैं: ENT_QUOTES एकल उद्धरण चिह्नों को भी बदल देता है (अन्यथा एकल उद्धरण चिह्नों से घिरा एक एट्रिब्यूट इंजेक्ट किए जाने योग्य बना रहता है), और ENT_SUBSTITUTE अमान्य UTF-8 अनुक्रमों को खाली स्ट्रिंग लौटाने के बजाय बदल देता है। PHP 8.1 से, दोनों फ़्लैग अंततः डिफ़ॉल्ट हैं, लेकिन उन्हें स्पष्ट रूप से लिखना आपके इरादे को प्रलेखित करता है और पुराने संस्करणों पर चलने वाले कोड की रक्षा करता है।

PHP
<?php
declare(strict_types=1);

$comment = $_GET['comment'] ?? '';

echo '<div>' . $comment . '</div>';

function e(string $value): string
{
    return htmlspecialchars(
        $value,
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    );
}

echo '<div>' . e($comment) . '</div>';
पहला आउटपुट भेद्य है, दूसरा सही ढंग से एस्केप किया गया है।

CSRF एक सरल तथ्य का फ़ायदा उठाता है: ब्राउज़र स्वतः ही आपके डोमेन की ओर किसी भी अनुरोध के साथ सेशन कुकीज़ जोड़ देता है, भले ही वह किसी तृतीय-पक्ष साइट से शुरू किया गया हो। इसलिए एक शत्रुतापूर्ण फ़ॉर्म पीड़ित के सेशन का उपयोग करके /account/delete सबमिट कर सकता है। क्लासिक बचाव है सिंक्रोनाइज़र टोकन: सेशन में संग्रहीत एक यादृच्छिक गुप्त वैल्यू जो हर बदलाव करने वाले अनुरोध में आवश्यक होती है। एक तृतीय-पक्ष साइट न तो इसे पढ़ सकती है और न ही अनुमान लगा सकती है, इसलिए वह इसे प्रदान नहीं कर सकती।

HTML
<?php
session_start();

if (!isset($_SESSION['csrf'])) {
    $_SESSION['csrf'] = bin2hex(random_bytes(32));
}

$sent = $_POST['csrf'] ?? '';
$valid = is_string($sent)
    && hash_equals($_SESSION['csrf'], $sent);

$isPost = $_SERVER['REQUEST_METHOD'] === 'POST';
if ($isPost && !$valid) {
    http_response_code(403);
    exit('Invalid CSRF token');
}
?>
<form method="post">
  <input type="hidden" name="csrf"
    value="<?= htmlspecialchars($_SESSION['csrf']) ?>">
  <button>Delete my account</button>
</form>
टोकन प्रति सेशन एक बार उत्पन्न होता है, किसी भी बदलाव वाली कार्रवाई से पहले सत्यापित किया जाता है।

SQL इंजेक्शन भी उसी पैटर्न का पालन करता है: किसी क्वेरी में उपयोगकर्ता की वैल्यू को जोड़ना उपयोगकर्ता को SQL लिखने देने के बराबर है - ' OR 1=1 -- एक फ़िल्टर को पूरी टेबल में बदल देता है। समाधान एस्केपिंग नहीं बल्कि प्रिपेयर्ड स्टेटमेंट है: क्वेरी का टेक्स्ट (अपने :email प्लेसहोल्डर के साथ) और वैल्यू इंजन तक अलग-अलग पहुँचते हैं, इसलिए वह कभी डेटा को कोड समझ नहीं सकता। एक विशेषज्ञ विवरण: MySQL के साथ, PDO डिफ़ॉल्ट रूप से प्रिपेयर्ड स्टेटमेंट का अनुकरण (emulate) करता है, क्लाइंट की ओर एस्केप करते हुए; वास्तव में नेटिव प्रिपेयर्ड स्टेटमेंट के लिए PDO::ATTR_EMULATE_PREPARES को false पर सेट करें।

PHP
<?php
declare(strict_types=1);

$pdo = new PDO('sqlite::memory:');
$pdo->setAttribute(
    PDO::ATTR_ERRMODE,
    PDO::ERRMODE_EXCEPTION
);
$pdo->exec(
    'CREATE TABLE users (
        id INTEGER PRIMARY KEY,
        email TEXT NOT NULL
    )'
);

$email = $_GET['email'] ?? '';

$stmt = $pdo->prepare(
    'SELECT id FROM users WHERE email = :email'
);
$stmt->execute(['email' => $email]);

var_dump($stmt->fetch(PDO::FETCH_ASSOC));
वैल्यू कभी SQL टेक्स्ट में शामिल नहीं होती: इंजेक्शन असंभव है।

ज्ञान जांच

सुनिश्चित करें कि आपको इस पाठ के मुख्य बिंदु याद हैं।

  1. htmlspecialchars को ENT_QUOTES फ़्लैग क्यों पास करें?
    • एकल उद्धरण चिह्नों को भी बदलने के लिए, जिसके बिना एकल उद्धरण चिह्नों से घिरा एक एट्रिब्यूट इंजेक्ट किए जाने योग्य बना रहता है
    • स्ट्रिंग को UTF-8 में बदलने के लिए विवश करने के लिए
    • सामग्री से स्क्रिप्ट टैग हटाने के लिए
    • लंबी स्ट्रिंग की एस्केपिंग को तेज़ करने के लिए
  2. CSRF टोकन की तुलना === के बजाय hash_equals से क्यों करें?
    • hash_equals स्थिर समय में तुलना करता है, जो प्रतिक्रिया समय मापकर टोकन का बाइट-दर-बाइट अनुमान लगाने से रोकता है
    • hash_equals तुलना करने से पहले टोकन के हैश की स्वतः पुनर्गणना करता है
    • === तब विफल हो जाता है जब दोनों स्ट्रिंग की एन्कोडिंग अलग हो
  3. प्रिपेयर्ड स्टेटमेंट को SQL इंजेक्शन से प्रतिरक्षित क्या बनाता है?
    • यह वैल्यू में मौजूद उद्धरण चिह्नों को स्वतः एस्केप कर देता है
    • क्वेरी और वैल्यू इंजन को अलग-अलग भेजे जाते हैं, जो वैल्यू को कभी SQL के रूप में पुनः व्याख्यायित नहीं करता
    • यह जाँचता है कि हर वैल्यू लक्ष्य कॉलम के टाइप से मेल खाती है
    • यह निष्पादन को एक ही SQL कथन तक सीमित करता है