मैं PHP में एसक्यूएल इंजेक्शन कैसे रोक सकता हूं?




mysql sql (19)

यदि उपयोगकर्ता इनपुट को SQL क्वेरी में संशोधन किए बिना डाला जाता है, तो अनुप्रयोग SQL इंजेक्शन के लिए कमजोर हो जाता है, जैसे कि निम्न उदाहरण में:

$unsafe_variable = $_POST['user_input']; 

mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");

ऐसा इसलिए है क्योंकि उपयोगकर्ता value'); DROP TABLE table;-- तरह कुछ इनपुट कर सकता है value'); DROP TABLE table;-- value'); DROP TABLE table;-- , और क्वेरी बन जाती है:

INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')

ऐसा होने से रोकने के लिए क्या किया जा सकता है?

https://code.i-harness.com


चेतावनी: इस उत्तर का नमूना कोड (प्रश्न के नमूना कोड की तरह) PHP के mysql एक्सटेंशन का उपयोग करता है, जिसे PHP 5.5.0 में बहिष्कृत किया गया था और पूरी तरह से PHP 7.0.0 में हटा दिया गया था।

यदि आप PHP के हालिया संस्करण का उपयोग कर रहे हैं, तो नीचे उल्लिखित mysql_real_escape_string विकल्प अब उपलब्ध नहीं होगा (हालांकि mysqli::escape_string एक आधुनिक समतुल्य है)। इन दिनों mysql_real_escape_string विकल्प केवल PHP के पुराने संस्करण पर विरासत कोड के लिए समझ में आएगा।

आपके पास दो विकल्प हैं - आपके unsafe_variable में विशेष वर्णों से बचने, या पैरामीटरयुक्त क्वेरी का उपयोग करना। दोनों आपको एसक्यूएल इंजेक्शन से बचाएंगे। पैरामीटरयुक्त क्वेरी को बेहतर अभ्यास माना जाता है लेकिन इसका उपयोग करने से पहले PHP में एक नए mysql एक्सटेंशन में बदलने की आवश्यकता होगी।

हम पहले से बचने वाले निचले प्रभाव स्ट्रिंग को कवर करेंगे।

//Connect

$unsafe_variable = $_POST["user-input"];
$safe_variable = mysql_real_escape_string($unsafe_variable);

mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

//Disconnect

mysql_real_escape_string फ़ंक्शन का विवरण भी देखें।

पैरामीटरयुक्त क्वेरी का उपयोग करने के लिए, आपको MySQL फ़ंक्शन के बजाय MySQLi का उपयोग करने की आवश्यकता है। अपने उदाहरण को फिर से लिखने के लिए, हमें निम्न की तरह कुछ चाहिए।

<?php
    $mysqli = new mysqli("server", "username", "password", "database_name");

    // TODO - Check that connection was successful.

    $unsafe_variable = $_POST["user-input"];

    $stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");

    // TODO check that $stmt creation succeeded

    // "s" means the database expects a string
    $stmt->bind_param("s", $unsafe_variable);

    $stmt->execute();

    $stmt->close();

    $mysqli->close();
?>

जिस कुंजी समारोह पर आप पढ़ना चाहते हैं वह mysqli::prepare

साथ ही, जैसा कि अन्य ने सुझाव दिया है, आप PDO जैसे कुछ के साथ अमूर्तता की एक परत को ऊपर उठाने के लिए उपयोगी / आसान पा सकते हैं।

कृपया ध्यान दें कि जिस मामले के बारे में आपने पूछा वह काफी सरल है और अधिक जटिल मामलों के लिए अधिक जटिल दृष्टिकोण की आवश्यकता हो सकती है। विशेष रूप से:

  • यदि आप उपयोगकर्ता इनपुट के आधार पर एसक्यूएल की संरचना को बदलना चाहते हैं, तो पैरामीटरयुक्त क्वेरी मदद करने वाली नहीं हैं, और आवश्यक mysql_real_escape_string द्वारा कवर नहीं है। इस तरह के मामले में, आप श्वेतसूची के माध्यम से उपयोगकर्ता के इनपुट को पारित करने से बेहतर होगा ताकि यह सुनिश्चित किया जा सके कि केवल 'सुरक्षित' मानों की अनुमति है।
  • यदि आप किसी शर्त में उपयोगकर्ता इनपुट से पूर्णांक का उपयोग करते हैं और mysql_real_escape_string दृष्टिकोण लेते हैं, तो आप नीचे दी गई टिप्पणियों में Polynomial द्वारा वर्णित समस्या से ग्रस्त होंगे। यह मामला ट्रिकियर है क्योंकि पूर्णांक उद्धरणों से घिरा नहीं होगा, इसलिए आप यह सत्यापित करके निपट सकते हैं कि उपयोगकर्ता इनपुट में केवल अंक हैं।
  • ऐसे कई अन्य मामले हैं जिनके बारे में मुझे जानकारी नहीं है। आपको लगता है कि this उन कुछ सूक्ष्म समस्याओं पर एक उपयोगी संसाधन है जो आप सामना कर सकते हैं।

जरूरी

एसक्यूएल इंजेक्शन को रोकने का सबसे अच्छा तरीका बचने के बजाय तैयार वक्तव्यों का उपयोग करना है, क्योंकि स्वीकृत उत्तर दर्शाता है।

Aura.Sql और EasyDB जैसे पुस्तकालय हैं जो डेवलपर्स को तैयार कथनों का उपयोग आसान बनाने की अनुमति देते हैं। एसक्यूएल इंजेक्शन को रोकने में तैयार कथन बेहतर क्यों हैं, इस बारे में और जानने के लिए, इस mysql_real_escape_string() बाईपास का संदर्भ लें और हाल ही में वर्डप्रेस में यूनिकोड एसक्यूएल इंजेक्शन भेद्यताएं तय करें

इंजेक्शन रोकथाम - mysql_real_escape_string()

इन हमलों को रोकने के लिए PHP ने विशेष रूप से बनाया गया कार्य किया है। आपको केवल एक फ़ंक्शन, mysql_real_escape_string के मुंह का उपयोग करना है।

mysql_real_escape_string एक स्ट्रिंग लेता है जो एक MySQL क्वेरी में उपयोग किया जा रहा है और उसी स्ट्रिंग को सभी SQL इंजेक्शन प्रयासों से सुरक्षित रूप से बचने के प्रयासों को वापस कर देता है। असल में, यह उन परेशान उद्धरणों को प्रतिस्थापित करेगा (') उपयोगकर्ता एक MySQL- सुरक्षित विकल्प, एक बच निकला उद्धरण \ "के साथ प्रवेश कर सकता है।

नोट: इस फ़ंक्शन का उपयोग करने के लिए आपको डेटाबेस से कनेक्ट होना चाहिए!

// MySQL से कनेक्ट करें

$name_bad = "' OR 1'"; 

$name_bad = mysql_real_escape_string($name_bad);

$query_bad = "SELECT * FROM customers WHERE username = '$name_bad'";
echo "Escaped Bad Injection: <br />" . $query_bad . "<br />";


$name_evil = "'; DELETE FROM customers WHERE 1 or username = '"; 

$name_evil = mysql_real_escape_string($name_evil);

$query_evil = "SELECT * FROM customers WHERE username = '$name_evil'";
echo "Escaped Evil Injection: <br />" . $query_evil;

आप MySQL - SQL इंजेक्शन रोकथाम में अधिक जानकारी प्राप्त कर सकते हैं।


जैसा कि आप देख सकते हैं, लोग सुझाव देते हैं कि आप सबसे अधिक तैयार कथन का उपयोग करें। यह गलत नहीं है, लेकिन जब आपकी क्वेरी प्रति प्रक्रिया केवल एक बार निष्पादित की जाती है, तो थोड़ा प्रदर्शन दंड होगा।

मुझे इस मुद्दे का सामना करना पड़ रहा था, लेकिन मुझे लगता है कि मैंने इसे बहुत परिष्कृत तरीके से हल किया - जिस तरह से हैकर्स उद्धरणों का उपयोग करने से बचने के लिए उपयोग करते हैं। मैंने इसे नकली तैयार बयान के संयोजन के साथ प्रयोग किया। मैं इसे सभी प्रकार के संभावित एसक्यूएल इंजेक्शन हमलों को रोकने के लिए उपयोग करता हूं।

मेरा दृष्टिकोण:

  • यदि आप इनपुट पूर्णांक होने की अपेक्षा करते हैं तो सुनिश्चित करें कि यह वास्तव में पूर्णांक है। एक चर-प्रकार की भाषा में PHP की तरह यह बहुत महत्वपूर्ण है। उदाहरण के लिए आप इस सरल लेकिन शक्तिशाली समाधान का उपयोग कर सकते हैं: sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);

  • यदि आप पूर्णांक हेक्स से कुछ और उम्मीद करते हैं । यदि आप इसे हेक्स करते हैं, तो आप पूरी तरह से सभी इनपुट से बच जाएंगे। सी / सी ++ में mysql_hex_string() नामक एक फ़ंक्शन है, PHP में आप bin2hex() उपयोग कर सकते हैं।

    इस बारे में चिंता न करें कि बच निकलने वाली स्ट्रिंग में इसकी मूल लंबाई का 2x आकार होगा क्योंकि यदि आप mysql_real_escape_string उपयोग करते हैं, तो PHP को समान क्षमता आवंटित करना होगा ((2*input_length)+1) , जो वही है।

  • जब आप बाइनरी डेटा स्थानांतरित करते हैं तो यह हेक्स विधि अक्सर उपयोग की जाती है, लेकिन मुझे कोई कारण नहीं दिखता कि एसक्यूएल इंजेक्शन हमलों को रोकने के लिए सभी डेटा पर इसका उपयोग क्यों न करें। ध्यान दें कि आपको 0x साथ डेटा UNHEX करना होगा या इसके बजाय MySQL फ़ंक्शन UNHEX उपयोग करना होगा।

तो, उदाहरण के लिए, क्वेरी:

SELECT password FROM users WHERE name = 'root'

हो जाएगा:

SELECT password FROM users WHERE name = 0x726f6f74

या

SELECT password FROM users WHERE name = UNHEX('726f6f74')

हेक्स एकदम सही भाग्य है। इंजेक्ट करने का कोई तरीका नहीं है।

यूएनएचएक्स फ़ंक्शन और 0 एक्स उपसर्ग के बीच अंतर

टिप्पणियों में कुछ चर्चा हुई, इसलिए मैं अंततः इसे स्पष्ट करना चाहता हूं। ये दो दृष्टिकोण बहुत समान हैं, लेकिन वे कुछ तरीकों से थोड़ा अलग हैं:

** 0x ** उपसर्ग का उपयोग केवल डेटा कॉलम जैसे चर, वर्कर, टेक्स्ट, ब्लॉक, बाइनरी आदि के लिए किया जा सकता है
इसके अलावा, यदि आप खाली स्ट्रिंग डालने वाले हैं तो इसका उपयोग थोड़ा जटिल है। आपको इसे पूरी तरह से '' से बदलना होगा, या आपको एक त्रुटि मिलेगी।

UNHEX () किसी भी कॉलम पर काम करता है; आपको खाली स्ट्रिंग के बारे में चिंता करने की ज़रूरत नहीं है।

हेक्स विधियों को अक्सर हमलों के रूप में उपयोग किया जाता है

ध्यान दें कि यह हेक्स विधि अक्सर SQL इंजेक्शन हमले के रूप में उपयोग की जाती है जहां पूर्णांक स्ट्रिंग की तरह होते हैं और केवल mysql_real_escape_string बच जाते हैं। फिर आप उद्धरण के उपयोग से बच सकते हैं।

उदाहरण के लिए, यदि आप ऐसा कुछ करते हैं:

"SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])

एक हमला आपको बहुत आसानी से इंजेक्ट कर सकता है । अपनी स्क्रिप्ट से दिए गए निम्नलिखित इंजेक्शन कोड पर विचार करें:

चुनें ... जहां id = -1 संघ सभी info_schema.tables से table_name का चयन करें

और अब टेबल संरचना निकालें:

चुनें ... जहां id = -1 संघ सभी info_schema.column से column_name का चयन करते हैं जहां table_name = 0x61727469636c65

और उसके बाद बस जो भी डेटा चाहते हैं चुनें। क्या यह अच्छा नहीं है?

लेकिन अगर इंजेक्शन योग्य साइट का कोडर हेक्स करेगा, तो कोई इंजेक्शन संभव नहीं होगा क्योंकि क्वेरी इस तरह SELECT ... WHERE id = UNHEX('2d312075...3635') : SELECT ... WHERE id = UNHEX('2d312075...3635')


जो कुछ भी आप समाप्त करते हैं, सुनिश्चित करें कि आप अपने इनपुट की जांच कर चुके हैं, पहले से ही magic_quotes या किसी अन्य अच्छी तरह से कचरा नहीं है, और यदि आवश्यक हो, तो इसे stripslashes माध्यम से चलाएं या जो भी इसे स्वच्छ करना है।


मेरी राय में, आम तौर पर आपके PHP अनुप्रयोग (या उस मामले के लिए कोई भी वेब एप्लिकेशन) में एसक्यूएल इंजेक्शन को रोकने का सबसे अच्छा तरीका है अपने एप्लिकेशन के आर्किटेक्चर के बारे में सोचना। यदि एसक्यूएल इंजेक्शन के खिलाफ सुरक्षा का एकमात्र तरीका एक विशेष विधि या फ़ंक्शन का उपयोग करना याद रखना है जो हर बार जब आप डेटाबेस से बात करते हैं, तो आप गलत कर रहे हैं। इस तरह, यह केवल समय की बात है जब तक कि आप अपने कोड में किसी बिंदु पर अपनी क्वेरी को सही रूप से प्रारूपित करना न भूलें।

एमवीसी पैटर्न को अपनाने और CakePHP या CodeIgniter जैसे ढांचे को शायद जाने का सही तरीका है: सुरक्षित डेटाबेस क्वेरी बनाने जैसे सामान्य कार्यों को हल किया गया है और इस तरह के ढांचे में केंद्रीय रूप से कार्यान्वित किया गया है। वे आपको अपने वेब एप्लिकेशन को एक समझदार तरीके से व्यवस्थित करने में मदद करते हैं और आपको एकल SQL क्वेरी सुरक्षित रूप से बनाने के बारे में ऑब्जेक्ट्स को लोड और सहेजने के बारे में अधिक सोचते हैं।


मैं पैरामीटरयुक्त SQL क्वेरी चलाने के लिए PDO (PHP डेटा ऑब्जेक्ट्स) का उपयोग करने की सलाह PDO

यह न केवल एसक्यूएल इंजेक्शन के खिलाफ सुरक्षा करता है, यह प्रश्नों को भी गति देता है।

और mysql_ , mysqli_ , और pgsql_ फ़ंक्शंस के बजाय पीडीओ का उपयोग करके, आप डेटाबेस pgsql_ को स्विच करने के लिए दुर्लभ घटना में, डेटाबेस से थोड़ा अधिक सारणी बनाते हैं।


PDO और तैयार प्रश्नों का प्रयोग करें।

( $conn एक PDO ऑब्जेक्ट है)

$stmt = $conn->prepare("INSERT INTO tbl VALUES(:id, :name)");
$stmt->bindValue(':id', $id);
$stmt->bindValue(':name', $name);
$stmt->execute();

तैयार बयान और पैरामीटरयुक्त प्रश्नों का प्रयोग करें। ये SQL कथन हैं जिन्हें किसी भी पैरामीटर से डेटाबेस सर्वर द्वारा अलग-अलग भेजा और पार्स किया जाता है। इस तरह हमलावर के लिए दुर्भावनापूर्ण एसक्यूएल इंजेक्ट करना असंभव है।

आपको मूल रूप से इसे प्राप्त करने के लिए दो विकल्प हैं:

  1. PDO का उपयोग करना (किसी समर्थित डेटाबेस ड्राइवर के लिए):

    $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
    
    $stmt->execute(array('name' => $name));
    
    foreach ($stmt as $row) {
        // do something with $row
    }
    
  2. MySQLi का उपयोग (MySQL के लिए):

    $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
    $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
    
    $stmt->execute();
    
    $result = $stmt->get_result();
    while ($row = $result->fetch_assoc()) {
        // do something with $row
    }
    

यदि आप MySQL के अलावा किसी अन्य डेटाबेस से कनेक्ट हो रहे हैं, तो एक ड्राइवर-विशिष्ट दूसरा विकल्प है जिसे आप PostgreSQL के लिए संदर्भित कर सकते हैं (उदाहरण के लिए pg_prepare() और pg_execute() )। पीडीओ सार्वभौमिक विकल्प है।

कनेक्शन को सही तरीके से स्थापित करना

ध्यान दें कि एक MySQL डेटाबेस तक पहुंचने के लिए PDO का उपयोग करते समय वास्तविक तैयार कथन डिफ़ॉल्ट रूप से उपयोग नहीं किया जाता है । इसे ठीक करने के लिए आपको तैयार बयानों के अनुकरण को अक्षम करना होगा। पीडीओ का उपयोग कर कनेक्शन बनाने का एक उदाहरण है:

$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

उपर्युक्त उदाहरण में त्रुटि मोड कड़ाई से जरूरी नहीं है, लेकिन इसे जोड़ने की सलाह दी जाती है । इस तरह जब कुछ गलत हो जाता है तो स्क्रिप्ट Fatal Error से नहीं रुक जाएगी। और यह डेवलपर को किसी भी त्रुटि को catch का मौका देता है जो PDOException एस के रूप में throw जाता है।

अनिवार्य है , हालांकि, पहली सेट setAttribute() लाइन है, जो पीडीओ को नकली तैयार बयान अक्षम करने और वास्तविक तैयार बयान का उपयोग करने के लिए कहती है। यह सुनिश्चित करता है कि MySQL सर्वर पर भेजने से पहले कथन और मानों को PHP द्वारा पार्स नहीं किया गया है (संभावित हमलावर को दुर्भावनापूर्ण SQL को इंजेक्ट करने का कोई मौका नहीं है)।

यद्यपि आप निर्माता के विकल्पों में charset सेट कर सकते हैं, यह ध्यान रखना महत्वपूर्ण है कि PHP (<5.3.6) के 'पुराने' संस्करणों ने चुपचाप डीएसएन में वर्णसेट पैरामीटर को अनदेखा कर दिया है

व्याख्या

क्या होता है कि आपके द्वारा तैयार किए जाने वाले SQL कथन को डेटाबेस सर्वर द्वारा पार्स और संकलित किया जाता है। मानकों को निर्दिष्ट करके (या तो एक ? या नामित पैरामीटर जैसे :name ऊपर दिए गए उदाहरण में :name ) आप डेटाबेस इंजन को बताते हैं जहां आप फ़िल्टर करना चाहते हैं। फिर जब आप execute , तो तैयार कथन आपके द्वारा निर्दिष्ट पैरामीटर मानों के साथ संयुक्त होता है।

यहां महत्वपूर्ण बात यह है कि पैरामीटर मान संकलित कथन के साथ संयुक्त होते हैं, न कि SQL स्ट्रिंग। एसक्यूएल इंजेक्शन स्क्रिप्ट को ट्रिक करके दुर्भावनापूर्ण तारों में काम करता है जब यह SQL को डेटाबेस भेजने के लिए बनाता है। तो पैरामीटर से अलग से वास्तविक एसक्यूएल भेजकर, आप जिस चीज का इरादा नहीं रखते थे उसके साथ समाप्त होने का जोखिम सीमित करते हैं। तैयार कथन का उपयोग करते समय आपके द्वारा भेजे जाने वाले किसी भी पैरामीटर को केवल स्ट्रिंग के रूप में माना जाएगा (हालांकि डेटाबेस इंजन कुछ अनुकूलन कर सकता है, इसलिए पैरामीटर निश्चित रूप से संख्याओं के रूप में भी समाप्त हो सकते हैं)। ऊपर दिए गए उदाहरण में, यदि $name चर में 'Sarah'; DELETE FROM employees 'Sarah'; DELETE FROM employees परिणाम परिणाम "'Sarah'; DELETE FROM employees" स्ट्रिंग के लिए खोज होगा "'Sarah'; DELETE FROM employees" , और आप एक खाली तालिका के साथ समाप्त नहीं होंगे।

तैयार बयानों का उपयोग करने का एक अन्य लाभ यह है कि यदि आप एक ही सत्र में कई बार एक ही कथन निष्पादित करते हैं तो इसे केवल एक बार पार्स और संकलित किया जाएगा, जिससे आपको कुछ गति लाभ मिलेगा।

ओह, और चूंकि आपने एक डालने के लिए इसे कैसे किया है, इसके बारे में पूछा है, यहां एक उदाहरण है (पीडीओ का उपयोग करके):

$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');

$preparedStatement->execute(array('column' => $unsafeValue));

तैयार कथन गतिशील प्रश्नों के लिए इस्तेमाल किया जा सकता है?

जबकि आप अभी भी क्वेरी पैरामीटर के लिए तैयार कथन का उपयोग कर सकते हैं, गतिशील क्वेरी की संरचना को parametrized नहीं किया जा सकता है और कुछ क्वेरी सुविधाओं को parametrized नहीं किया जा सकता है।

इन विशिष्ट परिदृश्यों के लिए, सबसे अच्छी बात यह है कि श्वेतसूची फ़िल्टर का उपयोग करें जो संभावित मानों को प्रतिबंधित करता है।

// Value whitelist
// $dir can only be 'DESC' otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
   $dir = 'ASC';
}

मुझे लगता है कि अगर कोई PHP और MySQL या कुछ अन्य डेटा का उपयोग करना चाहता हैबेस सर्वर:

  1. PDO (PHP डेटा ऑब्जेक्ट्स) सीखने के बारे में सोचें - यह एक डाटाबेस एक्सेस लेयर है जो एकाधिक डेटाबेस तक पहुंच की एक समान विधि प्रदान करता है।
  2. MySQLi सीखने के बारे में सोचोMySQLi
  3. मूल PHP फ़ंक्शंस का उपयोग करें जैसे: strip_tags , mysql_real_escape_string() या यदि वेरिएबल न्यूमेरिक, बस (int)$foohere PHP में चर के प्रकार के बारे में और पढ़ें । यदि आप पीडीओ या MySQLi जैसे पुस्तकालयों का उपयोग कर रहे हैं, तो हमेशा PDO::quote() और mysqli_real_escape_string()

पुस्तकालय उदाहरण:

---- पीडीओ

----- कोई प्लेसहोल्डर नहीं - एसक्यूएल इंजेक्शन के लिए परिपक्व! यह बुरा है

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values ($name, $addr, $city)");

----- अनाम प्लेसहोल्डर्स

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values (?, ?, ?);

----- नामित प्लेसहोल्डर्स

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) value (:name, :addr, :city)");

--- MySQLi

$request = $mysqliConnection->prepare('
       SELECT * FROM trainers
       WHERE name = ?
       AND email = ?
       AND last_login > ?');

    $query->bind_param('first_param', 'second_param', $mail, time() - 3600);
    $query->execute();

पीएस :

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

लेकिन पीडीओ और माईस्क्लुली दोनों तेजी से हैं, जबकि MySQLi मानक में तेजी से तेज़ी से प्रदर्शन करता है - गैर-तैयार बयानों के लिए ~ 2.5%, और तैयार लोगों के लिए ~ 6.5%।

और कृपया अपने डेटाबेस में प्रत्येक क्वेरी का परीक्षण करें - इंजेक्शन को रोकने के लिए यह एक बेहतर तरीका है।


मैं अपने वेब एप्लिकेशन को एसक्यूएल इंजेक्शन के प्रति संवेदनशील होने से रोकने के तीन अलग-अलग तरीकों का उपयोग करता हूं।

  1. उपयोग की mysql_real_escape_string(), में एक पूर्व निर्धारित समारोह है जो PHP : है, और इस कोड में निम्न वर्णों को बैकस्लैश जोड़ने \x00, \n, \r, \, ', "और \x1a। एसक्यूएल इंजेक्शन के मौके को कम करने के लिए इनपुट मानों को पैरामीटर के रूप में पास करें।
  2. पीडीओ का उपयोग करने का सबसे उन्नत तरीका है।

उम्मीद है इससे आपको मदद मिलेगी।

निम्नलिखित क्वेरी पर विचार करें:

$iId = mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

mysql_real_escape_string () यहां सुरक्षा नहीं करेगा। यदि आप अपनी क्वेरी के अंदर अपने चर के चारों ओर सिंगल कोट्स ('') का उपयोग करते हैं तो यह आपके खिलाफ सुरक्षा करता है। इसके लिए यहां एक समाधान दिया गया है:

$iId = (int) mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

इस question बारे में कुछ अच्छे जवाब हैं।

मेरा सुझाव है, पीडीओ का उपयोग करना सबसे अच्छा विकल्प है।

संपादित करें:

mysql_real_escape_string()PHP 5.5.0 के रूप में बहिष्कृत है। या तो mysqli या पीडीओ का प्रयोग करें।

Mysql_real_escape_string () का विकल्प है

string mysqli_real_escape_string ( mysqli $link , string $escapestr )

उदाहरण:

$iId = $mysqli->real_escape_string("1 OR 1=1");
$mysqli->query("SELECT * FROM table WHERE id = $iId");

** चेतावनी: इस उत्तर में वर्णित दृष्टिकोण केवल बहुत विशिष्ट परिदृश्यों पर लागू होता है और यह सुरक्षित नहीं है क्योंकि एसक्यूएल इंजेक्शन हमले न केवल इंजेक्ट करने में सक्षम होने पर भरोसा करते हैं X=Y। **

यदि हमलावर PHP के $_GETचर के माध्यम से या यूआरएल की क्वेरी स्ट्रिंग के माध्यम से फ़ॉर्म में हैक करने की कोशिश कर रहे हैं , तो वे सुरक्षित नहीं होने पर उन्हें पकड़ सकेंगे।

RewriteCond %{QUERY_STRING} ([0-9]+)=([0-9]+)
RewriteRule ^(.*) ^/track.php

क्योंकि 1=1, 2=2, 1=2, 2=1, 1+1=2, आदि ... एक हमलावर की एक SQL डेटाबेस के लिए आम सवाल कर रहे हैं। शायद यह कई हैकिंग अनुप्रयोगों द्वारा भी प्रयोग किया जाता है।

लेकिन आपको सावधान रहना चाहिए, कि आपको अपनी साइट से एक सुरक्षित क्वेरी को फिर से लिखना नहीं चाहिए। ऊपर दिया गया कोड आपको फिर से लिखने या रीडायरेक्ट करने के लिए एक टिप दे रहा है (यह आपके ऊपर निर्भर करता है) कि एक पृष्ठ में हैकिंग-विशिष्ट डायनामिक क्वेरी स्ट्रिंग जो हमलावर के आईपी ​​पते को स्टोर करेगी , या फिर उनकी कुकीज, इतिहास, ब्राउज़र या किसी भी अन्य संवेदनशील जानकारी, ताकि आप बाद में अपने खाते पर प्रतिबंध लगाकर या अधिकारियों से संपर्क कर सकें।


MYSQLi इंजेक्शन को रोकने के लिए PDO और MYSQLi का उपयोग करना एक अच्छा अभ्यास है, लेकिन यदि आप वास्तव में MySQL फ़ंक्शंस और प्रश्नों के साथ काम करना चाहते हैं, तो इसका उपयोग करना बेहतर होगा

mysql_real_escape_string()

$unsafe_variable = mysql_real_escape_string($_POST['user_input']);

इसे रोकने के लिए और अधिक क्षमताएं हैं: पहचान की तरह - यदि इनपुट एक स्ट्रिंग, संख्या, चार या सरणी है, तो इसका पता लगाने के लिए बहुत सारे अंतर्निहित कार्य हैं। साथ ही, इनपुट डेटा जांचने के लिए इन कार्यों का उपयोग करना बेहतर होगा।

is_string

$unsafe_variable = (is_string($_POST['user_input']) ? $_POST['user_input'] : '');

is_numeric

$unsafe_variable = (is_numeric($_POST['user_input']) ? $_POST['user_input'] : '');

और इनपुट डेटा को जांचने के लिए उन कार्यों का उपयोग करना इतना बेहतर है mysql_real_escape_string


आप कैश इंजन का लाभ लेने के चाहते हैं, जैसे Redis या Memcached , हो सकता है DALMP एक विकल्प हो सकता है। यह शुद्ध MySQLi का उपयोग करता है । इसे जांचें: PHP का उपयोग करके MySQL के लिए DALMP डेटाबेस एब्स्ट्रक्शन लेयर।

साथ ही, आप अपनी क्वेरी तैयार करने से पहले अपने तर्क तैयार कर सकते हैं ताकि आप गतिशील प्रश्न बना सकें और अंत में पूरी तरह से तैयार कथन क्वेरी हो। PHP का उपयोग कर MySQL के लिए DALMP डेटाबेस एब्स्ट्रक्शन लेयर।


इस PHP फ़ंक्शन का उपयोग करके mysql_escape_string()आप तेजी से एक अच्छी रोकथाम प्राप्त कर सकते हैं।

उदाहरण के लिए:

SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."'

mysql_escape_string - mysql_query में उपयोग के लिए एक स्ट्रिंग से बच निकलता है

अधिक रोकथाम के लिए, आप अंत में जोड़ सकते हैं ...

wHERE 1=1   or  LIMIT 1

अंत में आप पाते हैं:

SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."' LIMIT 1

एक अच्छा विचार है 'ऑब्जेक्ट-रिलेशनल मैपर' जैसे Idiorm :

$user = ORM::for_table('user')
->where_equal('username', 'j4mie')
->find_one();

$user->first_name = 'Jamie';
$user->save();

$tweets = ORM::for_table('tweet')
    ->select('tweet.*')
    ->join('user', array(
        'user.id', '=', 'tweet.user_id'
    ))
    ->where_equal('user.username', 'j4mie')
    ->find_many();

foreach ($tweets as $tweet) {
    echo $tweet->text;
}

यह न केवल आपको SQL इंजेक्शन से बचाता है बल्कि सिंटैक्स त्रुटियों से भी बचाता है! एक बार और एकाधिक कनेक्शन में कई परिणामों पर कार्रवाई को फ़िल्टर करने या लागू करने के लिए विधि श्रृंखला के साथ मॉडलों के संग्रह का भी समर्थन करता है।


एक आसान तरीका CodeIgniter या Laravel जैसे PHP ढांचे का उपयोग करना होगा जिसमें फ़िल्टरिंग और सक्रिय रिकॉर्ड जैसी अंतर्निहित सुविधाएं हों ताकि आपको इन बारीकियों के बारे में चिंता न करें।


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

अब, हमारा मुद्दा एसक्यूएल इंजेक्शन हमलों जैसे सुरक्षा खतरों को रोकने के लिए है (प्रश्न पूछने (PHP का उपयोग कर एसक्यूएल इंजेक्शन हमले को कैसे रोकें), अधिक यथार्थवादी, डेटा फ़िल्टरिंग या समाशोधन इनपुट डेटा ऐसे मामले में उपयोगकर्ता इनपुट डेटा का उपयोग करते समय मामला है प्रश्न, PHP या किसी अन्य प्रोग्रामिंग भाषा का उपयोग करना मामला नहीं है, या जैसा कि अधिक लोगों द्वारा तैयार किए गए कथन या वर्तमान में एसक्यूएल इंजेक्शन रोकथाम का समर्थन करने वाले किसी भी अन्य उपकरण का उपयोग करने के लिए अनुशंसित किया गया है, मान लें कि ये उपकरण अब उपलब्ध नहीं हैं? आप अपना आवेदन कैसे सुरक्षित करते हैं?

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

डेटा फ़िल्टरिंग (असुरक्षित डेटा को सुरक्षित डेटा में कनवर्ट करना) इस बात पर विचार करें कि PDO और MySQLi उपलब्ध नहीं हैं, आप अपना आवेदन कैसे सुरक्षित कर सकते हैं? क्या आप मुझे उनका उपयोग करने के लिए मजबूर करते हैं? PHP के अलावा अन्य भाषाओं के बारे में क्या? मैं सामान्य विचार प्रदान करना पसंद करता हूं क्योंकि यह विशिष्ट सीमा के लिए व्यापक सीमा के लिए उपयोग नहीं किया जा सकता है।

  1. एसक्यूएल उपयोगकर्ता (उपयोगकर्ता विशेषाधिकार सीमित): सबसे आम एसक्यूएल ऑपरेशंस (चयन, अद्यतन, INSERT) हैं, फिर, उस उपयोगकर्ता को अद्यतन विशेषाधिकार क्यों देना है जिसके लिए इसकी आवश्यकता नहीं है? उदाहरण के लिए लॉगिन, और खोज पृष्ठ केवल चयन का उपयोग कर रहे हैं, फिर, इन पृष्ठों में उच्च विशेषाधिकारों के साथ डीबी उपयोगकर्ताओं का उपयोग क्यों करें? नियम: सभी एसक्यूएल संचालन के लिए सभी विशेषाधिकारों के लिए एक डेटाबेस उपयोगकर्ता न बनाएं, आप आसानी से उपयोग के लिए उपयोगकर्ता नाम के रूप में अपनी योजना (डील्यूसर, चयनकर्ता, अद्यतनकर्ता) बना सकते हैं।

कम से कम विशेषाधिकार के सिद्धांत देखें

  1. डेटा फ़िल्टरिंग: किसी भी क्वेरी के निर्माण से पहले उपयोगकर्ता इनपुट को प्रोग्रामर के लिए मान्य और फ़िल्टर किया जाना चाहिए, प्रत्येक उपयोगकर्ता-इनपुट चर के लिए कुछ गुणों को परिभाषित करना महत्वपूर्ण है: डेटा प्रकार, डेटा पैटर्न और डेटा लंबाई । एक फ़ील्ड जो कि (x और y) के बीच एक संख्या है, एक स्ट्रिंग (टेक्स्ट) वाले फ़ील्ड के लिए सटीक नियम का उपयोग करके सटीक रूप से मान्य होना चाहिए: उदाहरण केस है, उदाहरण के लिए, उपयोगकर्ता नाम में केवल कुछ वर्ण होने चाहिए, [a- zA-Z0-9_-।] लंबाई (x और n) के बीच भिन्न होती है जहां x और n (integers, x <= n)। नियम: सटीक फ़िल्टर और सत्यापन नियम बनाना मेरे लिए सबसे अच्छा अभ्यास है।

  2. अन्य टूल्स का उपयोग करें: यहां, मैं आपसे सहमत हूं कि तैयार कथन (पैरामीट्रिज्ड क्वेरी) और संग्रहीत प्रक्रियाएं, यहां के नुकसान इन तरीकों से उन्नत कौशल की आवश्यकता है जो अधिकांश उपयोगकर्ताओं के लिए मौजूद नहीं हैं, मूलभूत विचार यहां SQL क्वेरी के बीच अंतर करना है और डेटा का उपयोग किया जा रहा है, दोनों दृष्टिकोणों का उपयोग असुरक्षित डेटा के साथ भी किया जा सकता है, क्योंकि उपयोगकर्ता-इनपुट डेटा मूल क्वेरी (जैसे कोई भी या x = x) में कुछ भी नहीं जोड़ता है। अधिक जानकारी के लिए, कृपया ओडब्ल्यूएएसपी एसक्यूएल इंजेक्शन रोकथाम धोखा शीट पढ़ें ।

अब, यदि आप एक उन्नत उपयोगकर्ता हैं, तो इस रक्षा का उपयोग अपनी पसंद के अनुसार शुरू करें, लेकिन शुरुआती लोगों के लिए, यदि वे संग्रहीत प्रक्रिया को जल्दी से कार्यान्वित नहीं कर सकते हैं और कथन तैयार कर सकते हैं, तो इनपुट डेटा को जितना संभव हो उतना फ़िल्टर करना बेहतर होगा।

अंत में, मान लें कि उपयोगकर्ता अपना उपयोगकर्ता नाम दर्ज करने के बजाय नीचे इस पाठ को भेजता है:

[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'

इस इनपुट को किसी भी तैयार कथन और संग्रहित प्रक्रियाओं के बिना जल्दी से चेक किया जा सकता है, लेकिन सुरक्षित पक्ष पर रहने के लिए, उनका उपयोग करके उपयोगकर्ता-डेटा फ़िल्टरिंग और सत्यापन के बाद शुरू होता है।

अंतिम बिंदु अप्रत्याशित व्यवहार का पता लगा रहा है जिसके लिए अधिक प्रयास और जटिलता की आवश्यकता है; सामान्य वेब अनुप्रयोगों के लिए इसकी अनुशंसा नहीं की जाती है। उपरोक्त उपयोगकर्ता इनपुट में अप्रत्याशित व्यवहार चयन, यूनियन, आईएफ, सबस्ट्रिंग, बेंचमार्क, एसएचए, रूट इन शब्दों के एक बार पता चला है, आप इनपुट से बच सकते हैं।

Update1:

एक उपयोगकर्ता ने टिप्पणी की कि यह पोस्ट बेकार है, ठीक है! यहां दिया गया है OWASP.ORG क्या प्रदान किया गया है:

प्राथमिक सुरक्षा:

विकल्प # 1: तैयार वक्तव्यों का उपयोग (पैरामीटरेटेड क्वेरीज़)
विकल्प # 2: संग्रहीत प्रक्रियाओं का उपयोग
विकल्प # 3: सभी उपयोगकर्ता समर्थित इनपुट से बचें

अतिरिक्त सुरक्षा:

भी लागू करें: कम विशेषाधिकार
भी प्रदर्शन करें: व्हाइट सूची इनपुट सत्यापन

जैसा कि आप जानते हैं, किसी लेख पर दावा करना वैध तर्क द्वारा समर्थित होना चाहिए, कम से कम एक संदर्भ! अन्यथा, इसे हमले और बुरे दावे के रूप में माना जाता है!

Update2:

PHP मैनुअल से, PHP: तैयार वक्तव्य - मैनुअल :

भागने और एसक्यूएल इंजेक्शन

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

एसक्यूएल इंजेक्शन को रोकने के लिए सर्वर के भीतर मूल्यों के स्वचालित भागने को कभी-कभी सुरक्षा सुविधा माना जाता है। अगर इनपुट मूल्य सही ढंग से बच निकले हैं तो गैर-तैयार बयान के साथ सुरक्षा की एक ही डिग्री हासिल की जा सकती है।

Update3:

मैंने तैयार बयान का उपयोग करते समय पीडीओ और MySQLi क्वेरी को MySQL सर्वर पर क्वेरी भेजने के लिए परीक्षण मामलों का निर्माण किया:

पीडीओ:

$user = "''1''"; //Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));

क्वेरी लॉग:

    189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
    189 Quit

MySQLi:

$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();

क्वेरी लॉग:

    188 Prepare   SELECT * FROM awa_user WHERE username =?
    188 Execute   SELECT * FROM awa_user WHERE username ='\'\'1\'\''
    188 Quit

यह स्पष्ट है कि एक तैयार कथन भी डेटा से बच रहा है, और कुछ नहीं।

जैसा कि उपर्युक्त कथन में भी उल्लेख किया गया है The automatic escaping of values within the server is sometimes considered a security feature to prevent SQL injection. The same degree of security can be achieved with non-prepared statements, if input values are escaped correctly, इसलिए, यह साबित करता है कि intval()क्वेरी सत्यापन भेजने से पहले डेटा सत्यापन को पूर्णांक मानों के लिए एक अच्छा विचार है, इसके अलावा, क्वेरी भेजने से पहले दुर्भावनापूर्ण उपयोगकर्ता डेटा को रोकना सही और मान्य दृष्टिकोण है

कृपया अधिक जानकारी के लिए यह प्रश्न देखें: पीडीओ MySQL को कच्ची क्वेरी भेजता है जबकि माईस्क्ली तैयार क्वेरी भेजता है, दोनों एक ही परिणाम उत्पन्न करते हैं

संदर्भ:

  1. एसक्यूएल इंजेक्शन धोखा शीट
  2. एसक्यूएल इंजेक्षन
  3. सूचना सुरक्षा
  4. सुरक्षा सिद्धांत
  5. डेटा मान्य

पीडीओ ( mysql_कार्यों से आने ) का उपयोग करने के बारे में अनिश्चित लोगों के लिए , मैंने एक बहुत ही सरल पीडीओ रैपर बनाया जो एक ही फाइल है। यह दिखाने के लिए मौजूद है कि सभी आम चीजों को करने की ज़रूरत है कि अनुप्रयोगों को कितना आसान करना है। PostgreSQL, MySQL, और SQLite के साथ काम करता है।

मूल रूप से, इसे PDO को PDO को PDO लिए पीडीओ फ़ंक्शंस को वास्तविक जीवन में उपयोग करने के तरीके को पढ़ने के लिए इसे PDO लिए इसे सरल बनाएं ताकि आप इच्छित प्रारूप में मूल्यों को स्टोर और पुनर्प्राप्त कर सकें ।

मुझे एक कॉलम चाहिए

$count = DB::column('SELECT COUNT(*) FROM `user`);

मुझे एक सरणी (कुंजी => मान) परिणाम चाहिए (यानी एक चयन बॉक्स बनाने के लिए)

$pairs = DB::pairs('SELECT `id`, `username` FROM `user`);

मुझे एक पंक्ति परिणाम चाहिए

$user = DB::row('SELECT * FROM `user` WHERE `id` = ?', array($user_id));

मुझे परिणामों की एक सरणी चाहिए

$banned_users = DB::fetch('SELECT * FROM `user` WHERE `banned` = ?', array(TRUE));

यदि संभव हो, तो अपने पैरामीटर के प्रकार डालें। लेकिन यह केवल int, bool, और float जैसे सरल प्रकारों पर काम कर रहा है।

$unsafe_variable = $_POST['user_id'];

$safe_variable = (int)$unsafe_variable ;

mysqli_query($conn, "INSERT INTO table (column) VALUES ('" . $safe_variable . "')");




sql-injection