मैं PHP के साथ उपयोगकर्ता इनपुट को कैसे सैनिटाइज़ कर सकता हूं?


1124

वहाँ कहीं एक catchall समारोह है कि SQL इंजेक्शन और XSS हमलों के लिए उपयोगकर्ता इनपुट sanitizing के लिए अच्छी तरह से काम करता है, जबकि अभी भी कुछ प्रकार के HTML टैग की अनुमति है?


42
आजकल, SQL इंजेक्शन से बचने के लिए, PDO या MySQLi का उपयोग करें।
फ्रांसिस्को प्रेसेनिया

76
PDO या MySQLi का उपयोग करना पर्याप्त नहीं है। यदि आप अपने SQL स्टेटमेंट का निर्माण बिना डेटा के करते हैं, जैसे select * from users where name='$name', तो यह कोई फर्क नहीं पड़ता कि आप PDO या MySQLi या MySQL का उपयोग करते हैं। आप अभी भी खतरे में हैं। आपको पैरामीट्रेटेड प्रश्नों का उपयोग करना चाहिए या, यदि आपको आवश्यक है, तो अपने डेटा पर भागने वाले तंत्र का उपयोग करें, लेकिन यह बहुत कम बेहतर है।
एंडी लेस्टर

26
@AndyLester क्या आप अनुमान लगा रहे हैं कि कोई व्यक्ति बिना तैयार किए गए बयानों के बिना पीडीओ का उपयोग करता है? :)

63
मैं कह रहा हूं कि "पीडीओ या माईएसक्यूएलआई का उपयोग करें" नौसिखियों को समझाने के लिए पर्याप्त जानकारी नहीं है कि उन्हें सुरक्षित रूप से कैसे उपयोग किया जाए। आप और मैं जानते हैं कि तैयार किए गए बयान मायने रखते हैं, लेकिन मुझे नहीं लगता कि जो कोई भी इस प्रश्न को पढ़ता है, वह इसे जानता होगा। इसीलिए मैंने स्पष्ट निर्देश जोड़े।
एंडी लेस्टर

30
एंडी की टिप्पणी पूरी तरह से वैध है। मैंने अपनी mysql वेबसाइट को पीडीओ में हाल ही में यह सोचकर परिवर्तित किया कि मैं अब इंजेक्शन के हमलों से किसी तरह सुरक्षित था। यह प्रक्रिया के दौरान ही मुझे एहसास हुआ कि मेरे कुछ sql स्टेटमेंट अभी भी उपयोगकर्ता इनपुट का उपयोग करके बनाए गए थे। मैंने तब तय किया कि तैयार बयानों का उपयोग करना। पूरी तरह से नौसिखिए के लिए, यह पूरी तरह से स्पष्ट नहीं है कि एक अंतर है क्योंकि कई विशेषज्ञ पीडीओ का उपयोग करने के बारे में टिप्पणी को फेंक देते हैं लेकिन तैयार बयानों की आवश्यकता को निर्दिष्ट नहीं करते हैं। यह माना जा रहा है कि यह स्पष्ट है। लेकिन नौसिखिए को नहीं।
घोस्ट राइडर

जवाबों:


1183

यह एक सामान्य गलत धारणा है कि उपयोगकर्ता इनपुट को फ़िल्टर किया जा सकता है। PHP में भी एक (अब पदावनत) "फीचर" है, जिसे मैजिक-कोट्स कहा जाता है , जो इस विचार को बनाता है। यह बकवास है। फ़िल्टर करने के बारे में भूल जाओ (या सफाई, या जो भी लोग इसे कहते हैं)।

समस्याओं से बचने के लिए आपको क्या करना चाहिए, यह काफी सरल है: जब भी आप विदेशी कोड के भीतर एक स्ट्रिंग एम्बेड करते हैं, तो आपको उस भाषा के नियमों के अनुसार, उससे बचना चाहिए। उदाहरण के लिए, यदि आप कुछ SQL में MySQL को लक्षित करने के लिए एक स्ट्रिंग एम्बेड करते हैं, तो आपको इस उद्देश्य के लिए MySQL के फ़ंक्शन के साथ स्ट्रिंग से बचना होगा ( mysqli_real_escape_string)। (या, डेटाबेस के मामले में, तैयार किए गए बयानों का उपयोग करना बेहतर तरीका है, जब संभव हो।)

एक अन्य उदाहरण HTML है: यदि आप HTML मार्कअप के भीतर तार एम्बेड करते हैं, तो आपको इसके साथ बचना चाहिए htmlspecialchars। इसका मतलब है कि हर एक echoया printबयान का उपयोग करना चाहिए htmlspecialchars

एक तीसरा उदाहरण शेल कमांड हो सकता है: यदि आप स्ट्रिंग्स (जैसे तर्क) को बाहरी कमांड में एम्बेड करने जा रहे हैं, और उन्हें कॉल करें exec, तो आपको उपयोग करना होगा escapeshellcmdऔर escapeshellarg

इत्यादि इत्यादि ...

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


245
"इसका मतलब है कि हर एक प्रतिध्वनि या प्रिंट स्टेटमेंट को htmlspecialchars का उपयोग करना चाहिए" - निश्चित रूप से, आपका मतलब है "हर ... स्टेटमेंट आउटपुट यूजर इनपुट"; htmlspecialchars () - ifying "गूंज 'हैलो, दुनिया!';" पागल हो जाएगा;)
बॉबी जैक

10
एक ऐसा मामला है जहां मुझे लगता है कि फ़िल्टर करना सही समाधान है: UTF-8। आप अपने आवेदन पर सभी के लिए UTF-8 अनुक्रमों को अमान्य नहीं चाहते हैं (आपको कोड पथ के आधार पर अलग-अलग त्रुटि पुनर्प्राप्ति मिल सकती है), और UTF-8 को आसानी से फ़िल्टर (या अस्वीकृत) किया जा सकता है।
कोर्नेल

6
@jbyrd - नहीं, LIKE एक विशेष regexp भाषा का उपयोग करता है। आपको अपने इनपुट स्ट्रिंग से दो बार बचना होगा - एक बार regexp के लिए और एक बार mysql स्ट्रिंग एन्कोडिंग के लिए। यह कोड के भीतर कोड है।
troelskn

6
इस समय mysql_real_escape_stringपदावनत है। एसक्यूएल इंजेक्शन को रोकने के लिए तैयार कथनों का उपयोग करना आजकल अच्छा अभ्यास माना जाता है । इसलिए या तो MySQLi या PDO पर स्विच करें।
मार्सेल कोर्पेल

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

217

इनपुट डेटा को सैनिटाइज़ करके SQL इंजेक्शन को रोकने की कोशिश न करें।

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

SQL इंजेक्शन को रोकने के बारे में अधिक जानकारी के लिए कृपया मेरी वेबसाइट http://bobby-tables.com/ देखें ।


18
या आधिकारिक दस्तावेज पर जाएं और पीडीओ और तैयार बयानों को जानें। छोटे सीखने की अवस्था, लेकिन यदि आप SQL को अच्छी तरह से जानते हैं, तो आपको आदत डालने में कोई परेशानी नहीं होगी।
एक कोडर

2
SQL इंजेक्शन के विशिष्ट मामले के लिए, यह सही उत्तर है!
स्कॉट आर्किसेवस्की

4
ध्यान दें कि तैयार किए गए बयानों में कोई सुरक्षा नहीं है, पैरामीटर किए गए प्रश्न हैं। वे बस PHP में एक साथ उपयोग करने के लिए बहुत आसान होने के लिए होते हैं।
बेसिक

इसका एकमात्र गारंटी तरीका नहीं है। हेक्स इनपुट और unxx क्वेरी में भी रोक देगा। इसके अलावा यदि आप सही हेक्सिंग का उपयोग करते हैं तो हेक्स हमले संभव नहीं हैं।
रेमन बाकर

क्या होगा यदि आप कुछ विशेष इनपुट कर रहे हैं, जैसे ईमेल पते या उपयोगकर्ता नाम?
अब्राहम ब्रुक्स

78

नहीं। आप डेटा को बिना किसी संदर्भ के जेनरेट नहीं कर सकते, इसके लिए क्या है। कभी-कभी आप इनपुट के रूप में SQL क्वेरी लेना चाहते हैं और कभी-कभी आप HTML को इनपुट के रूप में लेना चाहते हैं।

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

SQL के लिए डेटा से बचने की प्रक्रिया - SQL इंजेक्शन को रोकने के लिए - XSS को रोकने के लिए (X) HTML के लिए डेटा से बचने की प्रक्रिया से बहुत अलग है।


52

PHP के पास अब नया अच्छा फ़िल्टर_इन्पुट फ़ंक्शंस हैं, उदाहरण के लिए आपको 'अंतिम ई-मेल regex' खोजने से मुक्त करें अब एक अंतर्निहित FILTER_VALIDATE_EMAIL प्रकार है

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

/**
 *  Pork.FormValidator
 *  Validates arrays or properties by setting up simple arrays. 
 *  Note that some of the regexes are for dutch input!
 *  Example:
 * 
 *  $validations = array('name' => 'anything','email' => 'email','alias' => 'anything','pwd'=>'anything','gsm' => 'phone','birthdate' => 'date');
 *  $required = array('name', 'email', 'alias', 'pwd');
 *  $sanitize = array('alias');
 *
 *  $validator = new FormValidator($validations, $required, $sanitize);
 *                  
 *  if($validator->validate($_POST))
 *  {
 *      $_POST = $validator->sanitize($_POST);
 *      // now do your saving, $_POST has been sanitized.
 *      die($validator->getScript()."<script type='text/javascript'>alert('saved changes');</script>");
 *  }
 *  else
 *  {
 *      die($validator->getScript());
 *  }   
 *  
 * To validate just one element:
 * $validated = new FormValidator()->validate('blah@bla.', 'email');
 * 
 * To sanitize just one element:
 * $sanitized = new FormValidator()->sanitize('<b>blah</b>', 'string');
 * 
 * @package pork
 * @author SchizoDuckie
 * @copyright SchizoDuckie 2008
 * @version 1.0
 * @access public
 */
class FormValidator
{
    public static $regexes = Array(
            'date' => "^[0-9]{1,2}[-/][0-9]{1,2}[-/][0-9]{4}\$",
            'amount' => "^[-]?[0-9]+\$",
            'number' => "^[-]?[0-9,]+\$",
            'alfanum' => "^[0-9a-zA-Z ,.-_\\s\?\!]+\$",
            'not_empty' => "[a-z0-9A-Z]+",
            'words' => "^[A-Za-z]+[A-Za-z \\s]*\$",
            'phone' => "^[0-9]{10,11}\$",
            'zipcode' => "^[1-9][0-9]{3}[a-zA-Z]{2}\$",
            'plate' => "^([0-9a-zA-Z]{2}[-]){2}[0-9a-zA-Z]{2}\$",
            'price' => "^[0-9.,]*(([.,][-])|([.,][0-9]{2}))?\$",
            '2digitopt' => "^\d+(\,\d{2})?\$",
            '2digitforce' => "^\d+\,\d\d\$",
            'anything' => "^[\d\D]{1,}\$"
    );
    private $validations, $sanatations, $mandatories, $errors, $corrects, $fields;


    public function __construct($validations=array(), $mandatories = array(), $sanatations = array())
    {
        $this->validations = $validations;
        $this->sanitations = $sanitations;
        $this->mandatories = $mandatories;
        $this->errors = array();
        $this->corrects = array();
    }

    /**
     * Validates an array of items (if needed) and returns true or false
     *
     */
    public function validate($items)
    {
        $this->fields = $items;
        $havefailures = false;
        foreach($items as $key=>$val)
        {
            if((strlen($val) == 0 || array_search($key, $this->validations) === false) && array_search($key, $this->mandatories) === false) 
            {
                $this->corrects[] = $key;
                continue;
            }
            $result = self::validateItem($val, $this->validations[$key]);
            if($result === false) {
                $havefailures = true;
                $this->addError($key, $this->validations[$key]);
            }
            else
            {
                $this->corrects[] = $key;
            }
        }

        return(!$havefailures);
    }

    /**
     *
     *  Adds unvalidated class to thos elements that are not validated. Removes them from classes that are.
     */
    public function getScript() {
        if(!empty($this->errors))
        {
            $errors = array();
            foreach($this->errors as $key=>$val) { $errors[] = "'INPUT[name={$key}]'"; }

            $output = '$$('.implode(',', $errors).').addClass("unvalidated");'; 
            $output .= "new FormValidator().showMessage();";
        }
        if(!empty($this->corrects))
        {
            $corrects = array();
            foreach($this->corrects as $key) { $corrects[] = "'INPUT[name={$key}]'"; }
            $output .= '$$('.implode(',', $corrects).').removeClass("unvalidated");';   
        }
        $output = "<script type='text/javascript'>{$output} </script>";
        return($output);
    }


    /**
     *
     * Sanitizes an array of items according to the $this->sanitations
     * sanitations will be standard of type string, but can also be specified.
     * For ease of use, this syntax is accepted:
     * $sanitations = array('fieldname', 'otherfieldname'=>'float');
     */
    public function sanitize($items)
    {
        foreach($items as $key=>$val)
        {
            if(array_search($key, $this->sanitations) === false && !array_key_exists($key, $this->sanitations)) continue;
            $items[$key] = self::sanitizeItem($val, $this->validations[$key]);
        }
        return($items);
    }


    /**
     *
     * Adds an error to the errors array.
     */ 
    private function addError($field, $type='string')
    {
        $this->errors[$field] = $type;
    }

    /**
     *
     * Sanitize a single var according to $type.
     * Allows for static calling to allow simple sanitization
     */
    public static function sanitizeItem($var, $type)
    {
        $flags = NULL;
        switch($type)
        {
            case 'url':
                $filter = FILTER_SANITIZE_URL;
            break;
            case 'int':
                $filter = FILTER_SANITIZE_NUMBER_INT;
            break;
            case 'float':
                $filter = FILTER_SANITIZE_NUMBER_FLOAT;
                $flags = FILTER_FLAG_ALLOW_FRACTION | FILTER_FLAG_ALLOW_THOUSAND;
            break;
            case 'email':
                $var = substr($var, 0, 254);
                $filter = FILTER_SANITIZE_EMAIL;
            break;
            case 'string':
            default:
                $filter = FILTER_SANITIZE_STRING;
                $flags = FILTER_FLAG_NO_ENCODE_QUOTES;
            break;

        }
        $output = filter_var($var, $filter, $flags);        
        return($output);
    }

    /** 
     *
     * Validates a single var according to $type.
     * Allows for static calling to allow simple validation.
     *
     */
    public static function validateItem($var, $type)
    {
        if(array_key_exists($type, self::$regexes))
        {
            $returnval =  filter_var($var, FILTER_VALIDATE_REGEXP, array("options"=> array("regexp"=>'!'.self::$regexes[$type].'!i'))) !== false;
            return($returnval);
        }
        $filter = false;
        switch($type)
        {
            case 'email':
                $var = substr($var, 0, 254);
                $filter = FILTER_VALIDATE_EMAIL;    
            break;
            case 'int':
                $filter = FILTER_VALIDATE_INT;
            break;
            case 'boolean':
                $filter = FILTER_VALIDATE_BOOLEAN;
            break;
            case 'ip':
                $filter = FILTER_VALIDATE_IP;
            break;
            case 'url':
                $filter = FILTER_VALIDATE_URL;
            break;
        }
        return ($filter === false) ? false : filter_var($var, $filter) !== false ? true : false;
    }       



}

बेशक, इस बात का ध्यान रखें कि आपको अपनी sql क्वेरी को इस तरह से बचने की ज़रूरत है कि आपके द्वारा उपयोग किए जा रहे db के आधार पर (mysql_real_escape_string () उदाहरण के लिए sql सर्वर के लिए बेकार है)। आप शायद इसे अपने उपयुक्त एप्लिकेशन लेयर पर ORM की तरह स्वचालित रूप से हैंडल करना चाहते हैं। जैसा कि ऊपर बताया गया है: html के आउटपुट के लिए अन्य php समर्पित कार्यों जैसे htmlspecialchars;) का उपयोग करें;

वास्तव में अनुमत वर्गों और / या टैग के साथ HTML इनपुट की अनुमति के लिए समर्पित xss सत्यापन पैकेज में से एक पर निर्भर करता है। PARSE HTML के लिए अपने स्वयं के क्षेत्रों का निर्माण न करें!


17
ऐसा लगता है कि यह इनपुट को मान्य करने के लिए एक आसान स्क्रिप्ट हो सकती है, लेकिन यह सवाल के लिए पूरी तरह अप्रासंगिक है।
rjmunro

43

नहीं वहाँ नहीं है।

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

अंगूठे के बुनियादी नियम

  • SQL क्वेरी के लिए, मापदंडों (जैसे पीडीओ के साथ) को बांधें या क्वेरी चर (जैसे mysql_real_escape_string()) के लिए ड्राइवर-मूल बचने वाले फ़ंक्शन का उपयोग करें
  • strip_tags()अवांछित HTML को फ़िल्टर करने के लिए उपयोग करें
  • यहां अन्य htmlspecialchars()2 और 3 मानकों के साथ सभी अन्य आउटपुट से बचे रहें।

1
तो आप केवल स्ट्रिप_टैग्स () या एचटीएमएल स्पेशलचर्स () का उपयोग करते हैं जब आप जानते हैं कि इनपुट में एचटीएमएल है जिसे आप क्रमशः छुटकारा चाहते हैं या बच निकलना चाहते हैं - तो आप इसे किसी भी सुरक्षा उद्देश्य के लिए उपयोग नहीं कर रहे हैं? इसके अलावा, जब आप बाइंड करते हैं, तो यह बॉबी टेबल्स जैसे सामान के लिए क्या करता है? "रॉबर्ट '); DROP टेबल स्टूडेंट्स? -" क्या यह सिर्फ उद्धरण से बचता है?
रॉबर्ट मार्क ब्रैम

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

2
मेरे लिए सबसे अच्छा जवाब। यह छोटा है और यदि आप मुझसे पूछें तो प्रश्न को अच्छी तरह से संबोधित करेंगे। क्या कुछ इंजेक्शन के साथ $ _POST या $ _GET के माध्यम से PHP पर हमला करना संभव है या यह असंभव है?
जो स्मो

अरे हाँ, $ पोस्ट और $ सरण सभी पात्रों को स्वीकार करते हैं, लेकिन उन पात्रों में से कुछ का उपयोग आपके खिलाफ किया जा सकता है यदि चरित्र को पोस्ट किए गए php पृष्ठ में गणना करने की अनुमति है। इसलिए यदि आप अतिक्रमित वर्णों (जैसे ", 'और') से बच नहीं पाते हैं, तो यह एक हमले के वेक्टर को खोल सकता है।` वर्ण अक्सर छूट जाता है, और कमांड लाइन निष्पादन हैक बनाने के लिए इस्तेमाल किया जा सकता है। स्वच्छता उपयोगकर्ता इनपुट हैकिंग को रोक देगा। लेकिन वेब एप्लिकेशन फ़ायरवॉल हैक्स के साथ आपकी मदद नहीं करेगा।
drtechno

22

XSS समस्या को हल करने के लिए, HTML शोधकर्ता पर एक नज़र डालें । यह काफी विन्यास योग्य है और इसका एक अच्छा ट्रैक रिकॉर्ड है।

SQL इंजेक्शन हमलों के लिए, सुनिश्चित करें कि आप उपयोगकर्ता इनपुट की जांच करते हैं, और फिर इसे चलाते हैं हालांकि mysql_real_escape_string ()। हालाँकि, फ़ंक्शन सभी इंजेक्शन हमलों को नहीं हराएगा, इसलिए यह महत्वपूर्ण है कि आप डेटा को अपने क्वेरी स्ट्रिंग में डंप करने से पहले जांच लें।

एक बेहतर समाधान तैयार बयानों का उपयोग करना है। पीडीओ पुस्तकालय और mysqli विस्तार इन समर्थन करते हैं।


वहाँ कोई "सबसे अच्छा तरीका है" इनपुट sanitizing की तरह कुछ करने के लिए है .. कुछ पुस्तकालय का उपयोग करें, html शोधक अच्छा है। इन पुस्तकालयों को कई बार बनाया गया है। तो यह बहुत अधिक बुलेटप्रूफ है जितना कुछ भी आप अपने ऊपर आ सकते हैं
पान

Bioinformatics.org/phplabware/internal_utilities/htmLawed भी देखें । मेरी समझ से वर्डप्रेस एक पुराने संस्करण का उपयोग करता है, core.trac.wordpress.org/browser/tags/2.9.2/wp-includes/kses.php
स्टीव क्ले

वर्डप्रेस के साथ समस्या यह है कि इसके जरूरी php-sql इंजेक्शन अटैक नहीं है जो डेटाबेस ब्रीच का कारण बनता है। मिस प्रोग्राम्ड प्लगइन्स जो डेटा को स्टोर करते हैं जो कि एक xml क्वेरी से पता चलता है कि रहस्य अधिक समस्याग्रस्त है।
drtechno


17

एक चाल जो उस विशिष्ट परिस्थिति में मदद कर सकती है, जहाँ आपके पास एक पेज है /mypage?id=53और आप आईडी का उपयोग WHERE क्लॉज में करते हैं, यह सुनिश्चित करना है कि आईडी निश्चित रूप से एक पूर्णांक है, जैसे:

if (isset($_GET['id'])) {
  $id = $_GET['id'];
  settype($id, 'integer');
  $result = mysql_query("SELECT * FROM mytable WHERE id = '$id'");
  # now use the result
}

लेकिन निश्चित रूप से जो केवल एक विशिष्ट हमले को काटता है, इसलिए अन्य सभी उत्तरों को पढ़ें। (और हाँ मुझे पता है कि ऊपर दिया गया कोड महान नहीं है, लेकिन यह विशिष्ट रक्षा को दर्शाता है।)


11
मैं $ id = intval ($ id) का उपयोग करता हूं :)
Duc Tran

केवल पूर्णांक डेटा सम्मिलित करने के लिए कास्टिंग पूर्णांक एक अच्छा तरीका है।
टेस्ट

1
$id = (int)$_GET['id']और $que = sprintf('SELECT ... WHERE id="%d"', $id)बहुत अच्छा है
vladkras

16

PHP के साथ उपयोगकर्ता इनपुट sanitizing के लिए तरीके:

  • MySQL और PHP के आधुनिक संस्करणों का उपयोग करें।

  • स्पष्ट रूप से सेट करें:

    • $ Mysqli-> set_charset ( "UTF8");
      गाइड
    • $ pdo = नया PDO ('mysql: host = localhost; dbname = testdb; charset = UTF8', $ उपयोगकर्ता, $ पासवर्ड);
      गाइड
    • $ pdo-> निष्पादन ("सेट नाम utf8");
      गाइड
    • $ pdo = नया पीडीओ (
      "mysql: host = $ host; dbname = $ db", $ यूजर, $ पास, 
      सरणी (
      PDO :: ATTR_ERRMODE => PDO :: ERRMODE_EXCEPTION,
      PDO :: MYSQL_ATTR_INIT_COMMAND => "SAM NAMES utf8"
      )
      );
      गाइड
    • mysql_set_charset ( 'UTF8')
      [PHP 5.5.0 में हटाए गए PHP 5.5.0 में पदावनत]।
  • सुरक्षित वर्णमाला का उपयोग करें:

    • Utf8, latin1, ascii .. का चयन करें, असुरक्षित charsets big5, cp932, gb2312, gbk, sjis का उपयोग न करें।
  • स्थानिककृत फ़ंक्शन का उपयोग करें:

    • MySQLi ने तैयार किए बयान:
      $ stmt = $ mysqli-> तैयार ('का चयन करें * जहां से नाम का परीक्षण करें? सीमा 1'); 
      $ परम = "'या 1 = 1 / *";
      $ stmt-> bind_param ('s', $ param);
      $ stmt-> निष्पादित ();
    • पीडीओ :: उद्धरण () - स्थानों में इनपुट स्ट्रिंग के चारों ओर (यदि आवश्यक हो) और इनपुट स्ट्रिंग के भीतर विशेष वर्णों से बच जाता है, अंतर्निहित ड्राइवर के लिए उपयुक्त उद्धरण शैली का उपयोग करते हुए:

      $ pdo = नया PDO ('mysql: host = localhost; dbname = testdb; charset = UTF8', $ यूजर, $ पासवर्ड); स्पष्ट सेट वर्ण सेट
      $ pdo-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, गलत); MySQL के लिए मूल रूप से (इंजेक्शन को रोकने के लिए)
      $ var = $ pdo-> उद्धरण ("'या' 1 = 1 / *") को कम करने वाले बयानों को कम करने से रोकने के लिए तैयार किए गए अनुकरणीय बयानों को निष्क्रिय न करें ; न केवल शाब्दिक रूप से बच जाता है, बल्कि इसे उद्धृत भी करता है (एकल-भाव के पात्रों में) $ stmt = $ pdo-> क्वेरी ("चयन से परीक्षण जहां नाम = $ var लिमिट 1");

    • पीडीओ तैयार विवरण : बनाम MySQLi तैयार बयान अधिक डेटाबेस ड्राइवरों और नामित मापदंडों का समर्थन करता है:

      $ pdo = नया PDO ('mysql: host = localhost; dbname = testdb; charset = UTF8', $ यूजर, $ पासवर्ड); स्पष्ट सेट वर्ण सेट
      $ pdo-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, गलत); MySQL को मूल रूप से तैयार नहीं कर सकते हैं (इंजेक्शन को रोकने के लिए) $ stmt = $ pdo-> तैयार ('सेलेक्ट * FROM test WHERE name =? LIMIT 1'); $ stmt-> निष्पादित (["" या 1 = 1 / * "]);

    • mysql_real_escape_string [PHP 7.0.0 में हटाए गए PHP 5.5 में हटाए गए]।
    • mysqli_real_escape_string एसक्यूएल स्टेटमेंट में उपयोग के लिए एक स्ट्रिंग में विशेष पात्रों से बचता है, कनेक्शन के वर्तमान चार्ट को ध्यान में रखते हुए। लेकिन तैयार स्टेटमेंट का उपयोग करने की सिफारिश की गई है क्योंकि वे केवल तार से बच नहीं रहे हैं, एक बयान पूरी क्वेरी निष्पादन योजना के साथ आता है, जिसमें यह उपयोग करने वाले तालिकाओं और अनुक्रमित शामिल हैं, यह एक अनुकूलित तरीका है।
    • अपनी क्वेरी के अंदर अपने चर के आसपास एकल उद्धरण ('') का उपयोग करें।
  • वैरिएबल की जाँच करें कि आप क्या उम्मीद कर रहे हैं:

    • यदि आप पूर्णांक की अपेक्षा कर रहे हैं, तो उपयोग करें:
      ctype_digit - संख्यात्मक चरित्र (ओं) के लिए जाँच करें; 
      $ मूल्य = (इंट) $ मूल्य;
      $ मूल्य = इंटवल ($ मूल्य);
      $ var = filter_var ('0755', FILTER_VALIDATE_INT, $ विकल्प);
    • स्ट्रिंग्स उपयोग के लिए:
      is_string () - खोजें कि क्या चर का प्रकार स्ट्रिंग है

      फ़िल्टर फ़ंक्शन फ़िल्टर_वर () का उपयोग करें - एक निर्दिष्ट फ़िल्टर के साथ एक चर फ़िल्टर करें:
      $ ईमेल = filter_var ($ ईमेल, FILTER_SANITIZE_EMAIL); 
      $ newstr = filter_var ($ str, FILTER_SANITIZE_STRING);
      अधिक पूर्वनिर्धारित फ़िल्टर
    • filter_input () - नाम से एक विशिष्ट बाहरी चर हो जाता है और वैकल्पिक रूप से इसे फ़िल्टर करता है:
      $ search_html = filter_input (INPUT_GET, 'खोज', FILTER_SANITIZE_SPECIAL_CHARS);
    • preg_match () - एक नियमित अभिव्यक्ति मैच करें;
    • अपना स्वयं का सत्यापन कार्य लिखें।

11

आप यहाँ क्या वर्णन कर रहे हैं दो अलग मुद्दे हैं:

  1. उपयोगकर्ता इनपुट डेटा की स्वच्छता / फ़िल्टरिंग।
  2. उत्पादन से बचना।

1) उपयोगकर्ता इनपुट को हमेशा खराब माना जाना चाहिए।

तैयार किए गए कथनों का उपयोग करना, या / और mysql_real_escape_string के साथ फ़िल्टर करना निश्चित रूप से आवश्यक है। PHP में filter_input भी बनाया गया है जिसमें शुरू करने के लिए एक अच्छी जगह है।

2) यह एक बड़ा विषय है, और यह डेटा के आउटपुट के संदर्भ पर निर्भर करता है। HTML के लिए वहाँ htmlpurifier जैसे समाधान हैं। अंगूठे के एक नियम के रूप में, आप जो भी आउटपुट देते हैं उससे हमेशा बचकर रहें।

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

PHP आउटपुट तरीके

सुरक्षित PHP उत्पादन


9

यदि आप PostgreSQL का उपयोग कर रहे हैं, तो PHP से इनपुट pg_escape_string () के साथ बच सकता है

 $username = pg_escape_string($_POST['username']);

प्रलेखन से ( http://php.net/manual/es/function.pg-escape-string.php ):

pg_escape_string () डेटाबेस को क्वेरी करने के लिए एक स्ट्रिंग से बच जाता है। यह उद्धरण के बिना PostgreSQL प्रारूप में एक बचा हुआ स्ट्रिंग लौटाता है।


1
pg_escape_literal () PostgreSQL के लिए उपयोग करने के लिए अनुशंसित फ़ंक्शन है।
गुप्त

8

कोई कैटचेल फ़ंक्शन नहीं है, क्योंकि संबोधित करने के लिए कई चिंताएं हैं।

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

    बाहर की जाँच करें (केवल उचित) PDO ट्यूटोरियल के लिए बहुत ज्यादा सब कुछ आप PDO के बारे में जानने की जरूरत है। (इस विषय पर इस महान संसाधन के लिए शीर्ष SO योगदानकर्ता, @YourCommonSense के लिए ईमानदारी से धन्यवाद।)

  2. XSS - रास्ते में डेटा संचित करें ...

    • HTML शोधक एक लंबे समय के आसपास रहा है और अभी भी सक्रिय रूप से अपडेट किया गया है। आप इसका उपयोग दुर्भावनापूर्ण इनपुट को पवित्र करने के लिए कर सकते हैं, जबकि अभी भी टैग के उदार और विन्यास योग्य श्वेतसूची की अनुमति दे सकते हैं। कई WYSIWYG संपादकों के साथ काम करता है, लेकिन यह कुछ उपयोग मामलों के लिए भारी हो सकता है।

    • अन्य उदाहरणों में, जहाँ हम HTML / जावास्क्रिप्ट को बिल्कुल भी स्वीकार नहीं करना चाहते हैं, मुझे यह सरल कार्य उपयोगी लगा है (और XSS के विरुद्ध कई ऑडिट पास किए हैं):

      /* Prevent XSS input */ function sanitizeXSS () { $_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING); $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING); $_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST; }

  3. XSS - बाहर के रास्ते पर डेटा को सेनिटाइज़ करें ... जब तक आप डेटा को अपने डेटाबेस में जोड़ने से पहले ठीक से साफ-सफाई की गारंटी नहीं देते, आपको इसे अपने उपयोगकर्ता को प्रदर्शित करने से पहले इसे सैनिटाइज़ करने की आवश्यकता होगी, हम इन उपयोगी PHP कार्यों का लाभ उठा सकते हैं:

    • जब आप उपयोगकर्ता-आपूर्ति किए गए मूल्यों को कॉल echoया printप्रदर्शित करते हैं, htmlspecialcharsतब तक उपयोग करें जब तक कि डेटा ठीक से सुरक्षित नहीं था और HTML प्रदर्शित करने की अनुमति हो।
    • json_encode PHP से जावास्क्रिप्ट के लिए उपयोगकर्ता-प्रदत्त मूल्यों को प्रदान करने का एक सुरक्षित तरीका है
  4. क्या आप बाहरी शेल कमांड का उपयोग करके exec()या system()फ़ंक्शंस या backtickऑपरेटर को कॉल करते हैं ? यदि ऐसा है, तो SQL इंजेक्शन और XSS के अलावा, आपको अपने सर्वर पर दुर्भावनापूर्ण आदेश चलाने वाले उपयोगकर्ताओं को संबोधित करने के लिए एक अतिरिक्त चिंता हो सकती है । escapeshellcmdयदि आप संपूर्ण कमांड escapeshellargसे बचना चाहते हैं या व्यक्तिगत तर्कों से बचना चाहते हैं तो आपको इसका उपयोग करने की आवश्यकता है ।


इसके बजाय mb_encode_numericentity का उपयोग किया जा सकता है? चूंकि यह सब कुछ एनकोड करता है?
drtechno

@drtechno - # 3 XSSmb_encode_numericentityhtmlspecialchars
webaholik

5

इनपुट को सेनेटाइज करने और डेटा से बचने में गलतियों से बचने के लिए सबसे आसान तरीका है PHP फ्रेमवर्क जैसे कि सिम्फनी , नेट्टे आदि या उस फ्रेमवर्क का हिस्सा (टेम्प्लेटिंग इंजन, डेटाबेस लेयर, ORM)।

जैसे templating इंजन टहनी या लैटे उत्पादन डिफ़ॉल्ट रूप से चालू भागने है - आप को हल करने के लिए मैन्युअल रूप से अगर आप ठीक ढंग से संदर्भ (HTML या वेब पेज के जावास्क्रिप्ट हिस्सा) के आधार पर अपने उत्पादन बच गए नहीं है।

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

और डेटाबेस (मॉडल) लेयर के लिए ORM फ्रेमवर्क हैं जैसे कि Doctrine या PDO के आसपास रैपर जैसे Nette Database।

आप इसके बारे में अधिक यहां पढ़ सकते हैं - एक सॉफ्टवेयर ढांचा क्या है?


3

बस इसे आउटपुट से बचने के विषय में जोड़ना चाहते थे, यदि आप अपने html आउटपुट को बनाने के लिए php DOMDocument का उपयोग करते हैं तो यह स्वचालित रूप से सही संदर्भ में बच जाएगा। एक विशेषता (मान = "") और एक <span> का आंतरिक पाठ बराबर नहीं है। XSS के खिलाफ सुरक्षित रहने के लिए इसे पढ़ें: OWASP XSS प्रिवेंशन चीट शीट


2

आप इनपुट को कभी भी सैनिटाइज न करें।

आप हमेशा आउटपुट को सैनिटाइज करते हैं।

SQL कथन में सम्मिलित करने के लिए इसे सुरक्षित करने के लिए आप जिन परिवर्तनों पर डेटा लागू करते हैं, वे उन सभी से अलग हैं जिन्हें आप HTML में शामिल करने के लिए लागू करते हैं, उन सभी से बिल्कुल अलग हैं, जिन्हें आप जावास्क्रिप्ट में शामिल करने के लिए लागू करते हैं, उन सभी से अलग हैं जिन्हें आप LDIF में शामिल करते हैं। सीएसएस में शामिल करने के लिए आप उन लोगों से पूरी तरह से अलग हैं, जिन्हें आप एक ईमेल में शामिल करने से लागू होते हैं।

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

कुछ समय पहले किसी ने एक आकार का आविष्कार करने की कोशिश की, जो डेटा से बचने के लिए सभी तंत्र को फिट करता है और हमने " मैजिक_क्वाट्स " को समाप्त कर दिया, जो सभी आउटपुट लक्ष्यों के लिए डेटा को ठीक से बच नहीं पाया और परिणामस्वरूप अलग-अलग इंस्टॉलेशन को काम करने के लिए अलग कोड की आवश्यकता होती है।


इसके साथ एक समस्या यह है कि इसका हमेशा एक डेटाबेस हमला नहीं होता है, और सभी उपयोगकर्ता इनपुट को सिस्टम से संरक्षित किया जाना चाहिए। केवल एक भाषा प्रकार नहीं। तो अपनी साइटों पर, जब आप अपने $ _POST डेटा की गणना करते हैं, तब भी बाध्यकारी का उपयोग करते हुए, यह शेल या अन्य php कोड निष्पादित करने के लिए पर्याप्त रूप से बच सकता है।
drtechno

"इसका हमेशा डेटाबेस अटैक नहीं होता": "SQL स्टेटमेंट में शामिल करने के लिए इसे सुरक्षित करने के लिए आप जिन परिवर्तनों को डेटा पर लागू करते हैं, वे उन सभी से बिल्कुल अलग हैं ..."
सिम्बियन

"सभी उपयोगकर्ता इनपुट को सिस्टम से संरक्षित किया जाना चाहिए": कोई भी सिस्टम उपयोगकर्ता इनपुट से सुरक्षित नहीं होना चाहिए।
सिम्बियन

अच्छी तरह से मैं शब्दों से बाहर भाग गया, लेकिन हाँ इनपुट को सिस्टम ऑपरेशन को प्रभावित करने से रोकने की आवश्यकता है। इसे स्पष्ट करने के लिए ...
drtechno

इनपुट और आउटपुट दोनों को सैनिटाइज किया जाना चाहिए।
ताजनगरी

1

उपयोगकर्ता डेटा पर कभी भरोसा न करें।

function clean_input($data) {
  $data = trim($data);
  $data = stripslashes($data);
  $data = htmlspecialchars($data);
  return $data;
}

trim()समारोह को हटा खाली स्थान के और एक स्ट्रिंग के दोनों ओर से अन्य पूर्वनिर्धारित अक्षर।

stripslashes()समारोह बैकस्लैश को हटा

यह htmlspecialchars()फ़ंक्शन कुछ पूर्वनिर्धारित वर्णों को HTML संस्थाओं में परिवर्तित करता है।

पूर्वनिर्धारित वर्ण हैं:

& (ampersand) becomes &amp;
" (double quote) becomes &quot;
' (single quote) becomes &#039;
< (less than) becomes &lt;
> (greater than) becomes &gt;

1
इससे क्या रक्षा होगी? क्या यह XSS के लिए है? इसे क्यों कहा जाता है clean_input? आप स्लैश क्यों पट्टी करना चाहेंगे?
धर्म जूल

4
चेतावनी: यह जादुई रूप से उपयोगकर्ता डेटा को सुरक्षित नहीं करता है। यह फ़ंक्शन बिना किसी चीज़ की सुरक्षा के आपके डेटा को अनावश्यक रूप से नुकसान पहुंचाएगा। इसका प्रयोग न करें!
16

आपका कथन झूठा है।
एरिक थिअर्ट

0

वहाँ फिल्टर एक्सटेंशन ( howto- लिंक , मैनुअल ) है, जो सभी GPC चर के साथ बहुत अच्छी तरह से काम करता है। यह एक जादू-का-यह-यह सब नहीं है, हालांकि, आपको अभी भी इसका उपयोग करना होगा।

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