我有一个由教程制作的PDO数据库课程。 当我发送一个插入查询时,它中有一个绑定值的方法,实际上它是:
public function query($sql, $params = array()){
$this->_error = false;
if($this->_query = $this->_pdo->prepare($sql)){
if(count($params)){
$x = 1;
foreach($params as $param){
$this->_query->bindValue($x, $param);
$x++;
}
}
if($this->_query->execute()){
$this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ);
$this->_count = $this->_query->rowCount();
} else{
$this->_error = true;
}
}
return $this;
}
我遇到的问题是,我真的不明白这种绑定是如何工作的,我发送此查询:
DB::instance()->query("INSERT INTO table (column) VALUES (<script>alert('test');</script>)");
这是我的instance()方法:
public static function instance(){
if(!isset(self::$_instance)){
self::$_instance = new DB();
}
return self::$_instance;
}
现在的问题是,在我进入数据库表中的警报测试之后,然后我获取那条警报像一只非常疯狂的兔子一样跳起来的行:(。
我的问题是:这不是一个非常基本的SQL注入吗?为什么我能够将这样的脚本输入到数据库中?如何在不实际执行该脚本的情况下显示这些值?
谢谢你! :d
答案 0 :(得分:1)
您的代码中没有SQL注入,因为<script>alert('test');</script>
不是SQL。
准备好的语句只有在你正确使用它们时才会阻止SQL注入 - 它是一种可以更容易编写安全代码的工具,而不是检查你正在做什么的神奇子弹。您必须通过$params
数组提供所有不受信任的数据,而不是将其替换为查询。所以你应该这样做:
$DB::instance()->query("INSERT INTO table (column) VALUES (?)", ["<script>alert('test');</script>"]);
顺便说一下,没有必要在循环中调用bindValue()
。可以为execute()
方法提供一个参数数组作为参数,因此您可以这样做:
$this->_query->execute($params);
要防止在HTML网页中显示列时执行Javascript,请使用htmlentities()
:
echo htmlentities($row['column'], ENT_QUOTES);
这可以防止跨站点脚本(XSS)攻击。