我使用函数query()创建了这个类:
此函数使得使用预准备语句非常容易。但
我已经用sqlmap进行了测试,它看起来不错。
该函数基本将普通SELECT字符串拆分为多个较小的字符串以取消输入值。它保存输入值和字符串本身。字符串本身将被?替换。比正常的准备功能取代?再次输入值。
class dbcon
{
public $con;
public function __construct()
{
$this->con = new mysqli( $host, $username, $password, $dbname );
}
public function query( $query )
{
//selcet
if( strpos( $query, "SELECT" ) !== false )
{
$types = ""; $to_replace = []; $values = [];
$query = explode( "WHERE", $query );
$query_where = explode( "ORDER BY", $query[ '1' ] );
$query_where[ '0' ];
if( isset( $query_where[ '1' ] ) )
{
$ORDERBY = explode("LIMIT", $query_where[ '1' ]);
}
if( isset( $ORDERBY[ '1' ] ) )
{
$LIMIT = $ORDERBY[ '1' ];
}
$SELECT = $query[ '0' ];
$where = str_replace( array( "(", ")", "[", "]" ), "", $query_where[ '0' ] );
$where = str_replace( array( "AND", "OR", "and", "or" ), "-|-", $where );
$where = explode( "-|-", $where );
for ($i=0; $i < count($where); $i++) {
$for_where = str_replace( array( "!=", "<=", ">=", "=", "<>", ">", "<", "IS", "NOT LIKE", "LIKE" ), "#|#", $where[ $i ] );
$for_where = explode( "#|#", $for_where );
$value = trim( $for_where[ '1' ] );
if( substr_count($value, "AND") <= 0 AND substr_count($value, "OR") <= 0 )
{
$value = "'?'";
}
$to_replace[] = $value;
$value_num = "values".$i;
$$value_num = $value;
$values[] = &$$value_num;
$types .= "s";
}
$WHERE = str_replace( $to_replace , " ? ", $query_where[ '0' ] );
$prepare = $SELECT . " WHERE " . $WHERE;
if ( isset( $ORDERBY ) )
{
$prepare .= " ORDER BY " . $ORDERBY[ '0' ];
}
if ( isset( $LIMIT ) ){
$prepare .= " LIMIT " . $LIMIT;
}
$stmt = $this->con->prepare( $prepare );
//$stmt->bind_param($types, $values['0'],$values['1']);
call_user_func_array( array( $stmt, "bind_param" ), array_merge( array( $types ), $values ) );
$stmt->execute();
return $stmt->get_result();
$stmt->close();
}
}
}
$db = new dbcon();
调用函数:
$id = $_GET[ 'id' ];
$my_query = $db->query("SELECT * FROM Users WHERE ID = '$id' ORDER BY created DESC");
while($row = $my_query->fetch_array()){
echo $row['NAME']."<br>";
}
更新:
旧功能没有多大意义,根本不安全。这应该是一个简单的方法,但更好。
public function query( $query, $types, $query_values )
{
$values = [];
for ($i=0; $i < count($query_values); $i++) {
$value_num = "values".$i;
$$value_num = $query_values[ $i ];
$values[] = &$$value_num;
}
$stmt = $this->con->prepare( $query );
call_user_func_array( array( $stmt, "bind_param" ), array_merge( array( $types ), $values ) );
$stmt->execute();
return $stmt->get_result();
$stmt->close();
}
调用该函数
$query = "SELECT * FROM _Users WHERE ID = ? ORDER BY created ASC";
$my_query = $db->query( $query, "s", array( $id ) );
while($row = $my_query->fetch_array()){
echo $row['title']."<br>";
}
在您已经将值插入其中之后,您无法按照定义“准备”/“清理”/了解查询。
$my_query = $db->query("SELECT * FROM Users WHERE ID = '$id' ORDER BY created DESC");
那么如果有人尝试一些SQL注入会发生什么?例如:$id = "foo' OR '1' = '1"
:
SELECT * FROM Users WHERE ID = 'foo' OR '1' = '1' ORDER BY created DESC
在这之后的任何代码怎么可能理解这个查询应该做什么和它现在实际做什么之间的区别?这不可以。通过价值注入已经改变了意义。事后没有办法解决这个问题。