pdo - क्या PHP पीडीओ स्टेटमेंट टेबल या कॉलम नाम पैरामीटर के रूप में स्वीकार कर सकते हैं?




(6)

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

मैं टेबल पीडीओ स्टेटमेंट में टेबल नाम क्यों नहीं दे सकता?

$stmt = $dbh->prepare('SELECT * FROM :table WHERE 1');
if ($stmt->execute(array(':table' => 'users'))) {
    var_dump($stmt->fetchAll());
}

SQL क्वेरी में तालिका नाम डालने का कोई और सुरक्षित तरीका है? सुरक्षित के साथ मेरा मतलब है कि मैं नहीं करना चाहता

$sql = "SELECT * FROM $table WHERE 1"

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

SELECT name FROM my_table WHERE id = :value की योजना SELECT name FROM my_table WHERE id = :value वही होगा जो आप इसके लिए SELECT name FROM my_table WHERE id = :value :value , लेकिन प्रतीत होता है कि समान SELECT name FROM :table WHERE id = :value योजना नहीं बनाई जा सकती है, क्योंकि डीबीएमएस को पता नहीं है कि आप किस तालिका में हैं वास्तव में से चुनने जा रहे हैं।

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


मुझे लगता है कि यह एक पुरानी पोस्ट है, लेकिन मुझे यह उपयोगी लगता है और सोचा था कि मैं @kzqai के सुझाव के समान समाधान साझा करूंगा:

मेरे पास एक ऐसा फ़ंक्शन है जो दो पैरामीटर प्राप्त करता है ...

function getTableInfo($inTableName, $inColumnName) {
    ....
}

अंदर मैं यह सुनिश्चित करने के लिए सेट किए गए सरणी के खिलाफ जांच करता हूं कि केवल "धन्य" तालिकाओं वाले टेबल और कॉलम उपलब्ध हैं:

$allowed_tables_array = array('tblTheTable');
$allowed_columns_array['tblTheTable'] = array('the_col_to_check');

फिर पीडीओ चलाने से पहले PHP जांच की तरह दिखता है ...

if(in_array($inTableName, $allowed_tables_array) && in_array($inColumnName,$allowed_columns_array[$inTableName]))
{
    $sql = "SELECT $inColumnName AS columnInfo
            FROM $inTableName";
    $stmt = $pdo->prepare($sql); 
    $stmt->execute();
    $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
}

इस धागे में मुख्य प्रश्न के लिए, अन्य पदों ने यह स्पष्ट कर दिया कि क्यों हम वक्तव्य तैयार करते समय कॉलम नामों के मूल्यों को बाध्य नहीं कर सकते हैं, इसलिए यहां एक समाधान है:

class myPdo{
    private $user   = 'dbuser';
    private $pass   = 'dbpass';
    private $host   = 'dbhost';
    private $db = 'dbname';
    private $pdo;
    private $dbInfo;
    public function __construct($type){
        $this->pdo = new PDO('mysql:host='.$this->host.';dbname='.$this->db.';charset=utf8',$this->user,$this->pass);
        if(isset($type)){
            //when class is called upon, it stores column names and column types from the table of you choice in $this->dbInfo;
            $stmt = "select distinct column_name,column_type from information_schema.columns where table_name='sometable';";
            $stmt = $this->pdo->prepare($stmt);//not really necessary since this stmt doesn't contain any dynamic values;
            $stmt->execute();
            $this->dbInfo = $stmt->fetchAll(PDO::FETCH_ASSOC);
        }
    }
    public function pdo_param($col){
        $param_type = PDO::PARAM_STR;
        foreach($this->dbInfo as $k => $arr){
            if($arr['column_name'] == $col){
                if(strstr($arr['column_type'],'int')){
                    $param_type = PDO::PARAM_INT;
                    break;
                }
            }
        }//for testing purposes i only used INT and VARCHAR column types. Adjust to your needs...
        return $param_type;
    }
    public function columnIsAllowed($col){
        $colisAllowed = false;
        foreach($this->dbInfo as $k => $arr){
            if($arr['column_name'] === $col){
                $colisAllowed = true;
                break;
            }
        }
        return $colisAllowed;
    }
    public function q($data){
        //$data is received by post as a JSON object and looks like this
        //{"data":{"column_a":"value","column_b":"value","column_c":"value"},"get":"column_x"}
        $data = json_decode($data,TRUE);
        $continue = true;
        foreach($data['data'] as $column_name => $value){
            if(!$this->columnIsAllowed($column_name)){
                 $continue = false;
                 //means that someone possibly messed with the post and tried to get data from a column that does not exist in the current table, or the column name is a sql injection string and so on...
                 break;
             }
        }
        //since $data['get'] is also a column, check if its allowed as well
        if(isset($data['get']) && !$this->columnIsAllowed($data['get'])){
             $continue = false;
        }
        if(!$continue){
            exit('possible injection attempt');
        }
        //continue with the rest of the func, as you normally would
        $stmt = "SELECT DISTINCT ".$data['get']." from sometable WHERE ";
        foreach($data['data'] as $k => $v){
            $stmt .= $k.' LIKE :'.$k.'_val AND ';
        }
        $stmt = substr($stmt,0,-5)." order by ".$data['get'];
        //$stmt should look like this
        //SELECT DISTINCT column_x from sometable WHERE column_a LIKE :column_a_val AND column_b LIKE :column_b_val AND column_c LIKE :column_c_val order by column_x
        $stmt = $this->pdo->prepare($stmt);
        //obviously now i have to bindValue()
        foreach($data['data'] as $k => $v){
            $stmt->bindValue(':'.$k.'_val','%'.$v.'%',$this->pdo_param($k));
            //setting PDO::PARAM... type based on column_type from $this->dbInfo
        }
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);//or whatever
    }
}
$pdo = new myPdo('anything');//anything so that isset() evaluates to TRUE.
var_dump($pdo->q($some_json_object_as_described_above));

उपर्युक्त सिर्फ एक उदाहरण है, इसलिए कहने की जरूरत नहीं है, कॉपी-> पेस्ट काम नहीं करेगा। अपनी जरूरतों के लिए समायोजित करें। अब यह 100% सुरक्षा प्रदान नहीं कर सकता है, लेकिन यह कॉलम नामों पर कुछ नियंत्रण की अनुमति देता है जब वे गतिशील तारों के रूप में "अंदर आते हैं" और उपयोगकर्ताओं के अंत में बदला जा सकता है। इसके अलावा, आपके टेबल कॉलम नामों और प्रकारों के साथ कुछ सरणी बनाने की आवश्यकता नहीं है क्योंकि उन्हें info_schema से निकाला जाता है।


पीडीओ में पैरामीटर द्वारा टेबल और कॉलम नामों को प्रतिस्थापित नहीं किया जा सकता है।

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

function buildQuery( $get_var ) 
{
    switch($get_var)
    {
        case 1:
            $tbl = 'users';
            break;
    }

    $sql = "SELECT * FROM $tbl";
}

कोई डिफ़ॉल्ट केस छोड़कर या एक डिफ़ॉल्ट संदेश का उपयोग करके जो त्रुटि संदेश देता है, आप सुनिश्चित करते हैं कि केवल वही मान जिन्हें आप उपयोग करना चाहते हैं, का उपयोग करें।


अभिनव का सही और कामकाजी उत्तर है, मैं केवल विकल्प ऑब्जेक्ट में इसका उपयोग करने के लिए दूसरा विकल्प देना चाहता हूं (उदाहरण के लिए यदि आपके पास एक पृष्ठ पर एकाधिक ड्रॉपज़ोन अनुभाग हैं।)

myDropzone.options.dropzoneDivID = {
    sending: function(file, xhr, formData){
        formData.append('userName', 'Bob');
    }
};






php pdo