我是否从sql注射中拯救了自己?

时间:2010-08-30 15:45:54

标签: php mysql sql-injection

我这样做了吗?这有助于避免sql注入吗?

$deleteid = htmlspecialchars(strip_tags(mysql_real_escape_string($_POST['listid'])));

mysql_send("DELETE FROM stage where listid='$deleteid'");

7 个答案:

答案 0 :(得分:13)

没有

你应该只打电话给mysql_real_escape_string

htmlspecialcharsstrip_tags函数用于对要显示为HTML的字符串进行编码 它们不应该与SQL一起使用

答案 1 :(得分:8)

它可能会阻止SQL注入攻击,但它很难接近它。请改用prepared queries

由于您的评论表明您正在系统地对整个网站进行更改,因此请采用更好的方法。如果您正在使用它,您可能希望转移到非MySQL特定的数据库API,以防您以后想要切换到另一个后端。

答案 2 :(得分:3)

除了上面提到的建议(仅mysql_real_escape_string,但更好的预备语句),我想补充一点,确切地分析您要清理的值/总是有用的安全。

如果您的ID应该是一个整数,我只需使用intval($_POST['listid'])来确保结果为整数并为字符串保留mysql_real_escape_string(尽管我个人会使用预处理语句/ PDO)

答案 3 :(得分:2)

是的,对MySQL语句中的字符串声明中使用的值使用mysql_real_escape_string将阻止您进行SQL注入。这就是该功能的确切目的。

但您不需要其他两个函数strip_tagshtmlspecialchars。因为这些函数用于删除(HTML)标记并分别用字符引用替换HTML特殊字符。它们旨在保护您免受SQL注入。

事实上,在strip_tags之后使用htmlspecialchars和/或mysql_real_escape_string可以在某些特定情况下打破转义(例如,当使用基于非US-ASCII的字符集时,请参阅{ {3}})。因此,请确保在将其返回值插入SQL语句之前使用该函数。

除了使用mysql_real_escape_string对输出进行编码外,您还可以使用addslashes() Versus mysql_real_escape_string()验证输入:

if (ctype_digit($_POST['listid'])) {
    mysql_send("DELETE FROM stage where listid='".$_POST['listid']."'");
} else {
    // invalid value
}

此验证确保在查询中仅使用(正)整数值,不需要转义。

答案 4 :(得分:0)

我总是在我的所有项目中使用数据库助手类。这样我就不必使用mysql_real_escape_string来保持代码干净并且易于阅读如果您忘记使用它,您将无法进行注射

下面是我使用的一个例子......

<?php 
    final class DatabaseException extends Exception {
        function __construct($strErrMessage, $intErrCode) {
            parent::__construct($strErrMessage, $intErrCode);   
        }
    }

    class Database {
        protected $host     = ""; //database server
        protected $user     = ""; //database login name
        protected $pass     = ""; //database login password
        protected $database = ""; //database name
        protected $prefix   = ""; //table prefix        
        protected $connected = false;
        protected $db = null;   
        protected $record = array();
        protected $error = "";
        protected $errno = 0;

                //table name affected by SQL query
        protected $field_table= "";

        //number of rows affected by SQL query
        protected $affected_rows = 0;

        protected $link_id = 0;
        protected $query_id = array(); 

        function __construct($server, $user, $pass, $database, $pre='') {
            $this->connected = false;
            $this->host = $server;
            $this->user = $user;
            $this->pass = $pass;
            $this->database = $database;
            $this->prefix = $pre;
            $this->connect();
        }

        function __destruct() {
            //mysql_close($this->link_id); 
        }

        public function connect() {
            if ($this->link_id > 0 && $this->connected && mysql_ping($this->link_id)) { return; }

            $this->link_id = mysql_pconnect($this->host, $this->user, $this->pass);
            if (!$this->link_id) { //open failed
                throw new DatabaseException("mysql_pconnect failed",0);    
            }

            if(!@mysql_select_db($this->database, $this->link_id)) {//no database
                throw new DatabaseException("mysql_select_db failed",0); 
            }
            $this->server='';
            $this->user='';
            $this->pass='';
            $this->database=''; 
            $this->connected = true;
            $this->query("SET time_zone = '".Settings::get('db.timezone_offset')."';",TRUE);
        }

        public function escape($string) {
            if(get_magic_quotes_gpc()) 
                $string = stripslashes($string);
            return mysql_real_escape_string($string);
        }

        public function insert($table,$data,$tbl_key='id') {
            $v=''; 
            $n='';
            foreach($data as $key=>$val) {
                $n.="`$key`, ";
                if(strtolower($val)=='null') 
                    $v.="NULL, ";
                elseif(strtolower($val)=='now()') 
                    $v.="NOW(), ";
                elseif(strcmp(substr($val,0,7),'**ESC**') == 0) 
                    $v .= str_replace('**ESC**','',$val);
                else 
                    $v.= "'".$this->escape($val)."', ";
            }

            if ($v=='' || $n=='') 
                return false;

            $q  = "INSERT INTO `".$this->prefix.$table."` ";
            $q .= "(". rtrim($n, ', ') .") VALUES (". rtrim($v, ', ') .");";
            if($this->query($q)){
                $id=mysql_insert_id();
                if ($id === 0) {  // The ID generated for an AUTO_INCREMENT column by the previous INSERT query on success, 
                                  // 0 if the previous query does not generate an AUTO_INCREMENT value, or FALSE if no MySQL 
                                  // connection was established.
                    return TRUE;
                } 
                return $id;
            }
            else {
                return false;
            }
        }

        public function replace($table,$data,$tbl_key='id') {
            $v=''; 
            $n='';
            foreach($data as $key=>$val) {
                $n.="`$key`, ";
                if(strtolower($val)=='null') 
                    $v.="NULL, ";
                elseif(strtolower($val)=='now()') 
                    $v.="NOW(), ";
                elseif(strcmp(substr($val,0,7),'**ESC**') == 0) 
                    $v .= str_replace('**ESC**','',$val);
                else 
                    $v.= "'".$this->escape($val)."', ";
            }

            if ($v=='' || $n=='') 
                return false;

            $q  = "REPLACE INTO `".$this->prefix.$table."` ";
            $q .= "(". rtrim($n, ', ') .") VALUES (". rtrim($v, ', ') .");";

            if($this->query($q)){
                $id=mysql_insert_id();
                if ($id === 0) {  // The ID generated for an AUTO_INCREMENT column by the previous INSERT query on success, 
                                  // 0 if the previous query does not generate an AUTO_INCREMENT value, or FALSE if no MySQL 
                                  // connection was established.
                    return TRUE;
                } 
                return $id;
            }
            else {
                return false;
            }
        }

        public function update($table,$data,$where='1') {
            $q = "UPDATE `".$this->prefix.$table."` SET ";
            foreach($data as $key=>$val) {
                if(strtolower($val)=='null') $q .= "`$key` = NULL, ";
                elseif(strtolower($val)=='now()') $q .= "`$key` = NOW(), ";
                elseif(strcmp(substr($val,0,7),'**ESC**') == 0) $q .=  "`$key` = ".str_replace('**ESC**','',$val);
                else $q.= "`$key`='".$this->escape($val)."', ";
            }
            $q = rtrim($q, ', ') . ' WHERE '.$where.';';
            $result = $this->query($q); 

            if ($result) {
            }
            return $result;
        }

        public function search($table, $field, $value, $exact=FALSE)
        {
                    $value = escape($value);
            if (!$exact) {      
                $q = "select * from $table where $field like '%$value%';";
            } else {
                $q = "select * from $table where $field = '$value';";
            }
            return $this->query($q);
        }

        public function delete($table,$where='1') {
            $q  = "DELETE FROM `".$this->prefix.$table."` ";
            $q .= " WHERE ".$where.";";
            $result = $this->query($q);             

            if ($result) {
            }
        }

        public function query($sql,$reset=FALSE) {
            //echo "<pre>$sql</pre>";
            $this->connect();
            $command = strtok(trim($sql)," \n\t");
            switch (strtoupper(trim($command))) {
                case "SELECT":
                case "SHOW":
                case "DESCRIBE":
                case "EXPLAIN":
                    if (isset($this->query_id[md5($sql)]) && $reset==FALSE) {
                        $row = mysql_fetch_array($this->query_id[md5($sql)], MYSQL_ASSOC);
                        if ($row == FALSE) {
                            unset($this->query_id[md5($sql)]);
                            return FALSE;
                        } else {
                            return $row;
                        }
                    } else {    
                        $this->query_id[md5($sql)] = @mysql_query($sql, $this->link_id);
                        if (!$this->query_id[md5($sql)]) {
                            throw new DatabaseException(mysql_error($this->link_id),mysql_errno($this->link_id));
                        }
                    }
                    $row = mysql_fetch_array($this->query_id[md5($sql)], MYSQL_ASSOC);
                    if ($row == FALSE) {
                        unset($this->query_id[md5($sql)]);
                        return FALSE;
                    } else {
                        return $row;
                    }
                    break;
                default:
                    return @mysql_query($sql, $this->link_id);
                    break;
            }
        }
    }
?>

创建和使用数据库类:

$db = new Database("db.host","db.user","db.pass","db.database");

如果所有表单元素的名称与表字段相同,则将$_POST中的数据导入数据库非常简单。例如:

$data = $_POST;
$ok = $db->update('mytable', $data, 'something = something_else'); //$ok will be false if something went wrong

答案 5 :(得分:0)

在这种情况下

mysql_query("DELETE FROM stage WHERE listid=".intval($_POST['listid']));

完整参考:dynamical SQL syntax explained

答案 6 :(得分:-1)

使用存储过程并仅向您的app db用户授予执行权限(以及sprocs带来的无数其他好处)