如何保护ODBC查询不受SQL注入的影响


How to protect an ODBC query from SQL injection

保护此查询免受sql注入的最佳方法是什么?这个例子只是一个例子,我在互联网上读了一些文章,但无法理解参数化查询。任何有用文章的链接都会得到投票,但我认为看到这个例子会对我帮助最大。

$id = $_GET["id"];
$connection = odbc_connect("Driver={SQL Server};Server=SERVERNAME;Database=DATABASE-NAME;", "USERNAME", "PASSWORD");
$query = "SELECT id firstname secondname from user where id = $id";
$result = odbc_exec($connection, $query);
while ($data[] = odbc_fetch_array($result));
odbc_close($connection);

谢谢,

编辑:我没有说清楚,但我使用的是SQL Server,而不是mysql。这只是一个例子,它不会总是我搜索的数字。如果答案像许多人建议的那样使用参数化查询,那就太好了,而且对于所有查询都是一样的,而不是对于不同类型的用户输入进行不同类型的验证。

我认为PDO对象是最好的。

简而言之,以下是如何使用它们。

$databaseConnection = new PDO('mysql:host='. $host .';dbname=' . $databaseName, $username, $password);
$sqlCommand = 'SELECT foo FROM bar WHERE baz=:baz_value;';
$parameters = array(
    ':baz_value'    => 'some value'
);
$preparedStatement = $databaseConnection->prepare($sqlCommand);
$preparedStatement->execute($parameters);
while($row = $preparedStatement->fetch(PDO::FETCH_ASSOC))
{
    echo $row['foo'] . '<br />';
}

您为SELECT条件输入的值将替换为以冒号开头的参数(如:field_value)。然后在一个单独传递的数组中为参数赋值。

在我看来,这是一种更好的处理SQL查询的方法。

参数与查询分开发送到数据库,并防止SQL注入。

使用准备好的语句。首先使用odbc_prepare()函数构建一个语句,然后将参数传递给它,并使用odbc_execute()执行它。

这比自己逃离字符串更安全、更容易。

Lewis Bassett关于PDO的建议是好的,但是可以在ODBC中使用准备好的语句,而不必切换到PDO。

示例代码,未经测试

try {
  $dbh = new PDO(CONNECTION_DETAILS_GO_HERE);
  $query = 'SELECT id firstname secondname from user where id = :id';
  $stmt = $dbh->prepare($query);
  $stmt->bindParam(':id', $id, PDO::PARAM_STR);
  $result = $stmt->execute();
  $data = $stmt->fetchAll();
} catch (PDOException $e)
  echo 'Problem: ', $e->getMessage;
}

注意:$e->getMessage();可能会暴露你不想暴露的东西,所以当你的代码上线时,你可能会想在这一行做一些不同的事情。不过,它对调试很有用。

编辑:不确定您想要的是PDO还是ODBC示例,但两者基本相同。

编辑:如果你对我投了反对票,请留言告诉我原因。

首先,要小心查询中使用的变量,特别是那些来自外部来源的变量,如$_GET、$_POST、$_COOKIE和$_FILES。为了在查询中使用变量,您应该:

  • 将数字数据强制转换为整数或浮点(以合适的为准)
  • 使用适当的转义来转义其他数据

mysql数据库的一个简单示例:

$id = $_GET["id"];     // contains: OR 1 = 1
$name = $_GET["name"]; // contains: ' OR '' ='
$query = "SELECT * FROM table WHERE id = " . intval($id) . " AND name = '" . mysql_real_escape_string($name) . "'";
// SELECT * FROM table WHERE id = 0 AND name = ''' OR '''' ='''

对于其他数据库,转义做法各不相同。但通常情况下,您应该使用''来转义'字符,因此:

$id = $_GET["id"];     // contains: OR 1 = 1
$name = $_GET["name"]; // contains: ' OR '' ='
$query = "SELECT * FROM table WHERE id = " . intval($id) . " AND name = '" . str_replace("'", "''", $name) . "'";
// SELECT * FROM table WHERE id = 0 AND name = ''' OR '''' ='''

话虽如此,也许您可能想改用PDO。它允许您使用准备好的语句,PDO驱动程序完成所有的转义。

mysql变体附带了一个名为mysql_real_sescape_string的方法,该方法适用于目标SQL版本。你能做的最好的事情就是编写一个方法来转义Id。重要的是你的转义方法适合目标数据库。您还可以对数字输入执行is_numeric等基本类型检查,这将立即拒绝SQL字符串注入。

请参阅如何使用PHP在SQL Server中转义字符串?并遵循一些相关链接以获取显式示例