最初,我使用mysql_connectmysql_query做事情。然后我学习了SQL注入,因此我试图学习如何使用准备好的语句。我了解PDO类的prepare和execute函数如何用于防止SQL注入。

仅当用户输入存储到数据库中时才需要准备好的语句吗?仍然可以使用mysql_num_rows,因为我真的不冒使用该功能被黑客入侵的风险吗?还是使用准备好的语句执行此操作更安全?我应该为涉及MySQL的所有事情使用准备好的语句吗?为什么?

评论

如果您不能保证代码库中的任何部分都不会使用用户生成的查询数据,那就没有什么意义了。如果您只有一个查询,则没有必要使用两种不同的方式来形成查询。首先处理预先准备好的安全性查询,然后进行一致性查询。

您似乎有些困惑。首先,请不要使用mysql_ *; mysql_ *函数已过时,过时和不安全。改用MySQLi或PDO。其次,mysql_num_rows与准备好的语句无关,并且不是PDO功能。您可以在运行查询之前准备语句,而不要在要计算行时在语句之后准备。

#1 楼

tl / dr

总是。 100%的时间使用它。总是;即使您不需要使用它。仍然使用它。


mysql_*函数已弃用。 (注意红色的大框吗?)警告

PHP 5.5.0中已弃用该扩展名,并且在PHP 7.0.0中已将其删除
。相反,应该使用MySQLi或PDO_MySQL扩展名
。另请参阅MySQL:选择API指南和相关的FAQ,以获取更多信息。此功能的替代方法包括:


mysqli_connect()
PDO :: __ construct()



最好使用PDOMySQLi。使用预准备语句时,这些2中的任何一个都足以作为兼容库。

在没有预准备语句/未经消毒的情况下信任用户输入就像将您的汽车放在不安全的地方,被解锁并带有点火钥匙。您基本上是说,请进来拿我的东西

您永远不应该,而且我的意思是永远不要信任用户输入。除非您要这样:



如注释中所述,参考数据并存储它,您永远也永远不应信任任何与用户相关的输入。除非您有101%的把握将用于操纵所述数据库/值的数据硬编码到您的应用中,否则您必须使用准备好的语句。

现在介绍为什么应该使用准备好的语句。这很简单。防止SQL注入,但是以最直接的方式。准备好的语句的工作方式很简单,它将查询和数据一起发送,但是是分开的(如果有意义的话哈哈)-我的意思是:

Prepared Statements
Query: SELECT foo FROM bar WHERE foo = ?
Data:  [? = 'a value here']


与它的前一个版本相比,在前一个版本中您将数据与查询一起截断,然后将其作为一个整体发送,这意味着将其作为单个事务执行,从而导致SQL注入漏洞。

以下是一个伪PHP PDO示例,向您展示了预准备语句/绑定的简单性。

$dbh = PDO(....); // dsn in there mmm yeahh
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

// insert one row
$name = 'one';
$value = 1;
$stmt->execute();


摘自PHP手册,用于PDO预准备语句


更多阅读内容


如何防止php中的SQL注入?
什么是SQL注入? (简单术语)


评论


@Darren我想知道我是否正确。在只有固定值的地方是否需要使用准备好的语句?例如,某人需要批准或拒绝一个请求,而此人获得的唯一输入就是2个按钮的选择:批准和拒绝,并且每个按钮上的写入值都是固定的。我需要在此处使用准备好的语句吗?注意:该页面不会为用户提供用户输入任何文本的可能性。

– BRoebie
2015年12月3日,12:24

@BRoebie安全起来总比对不起好。用户可以与通过其传递的数据(即表单)进行交互的任何地方,本质上都应该准备语句。如果您要从易于通过元素检查等修改的输入中获取上述值,那么您可能会遇到很多麻烦。

–达伦
2015年12月3日23:34

@Darren,我同意。我想知道是否我是否需要使用准备好的语句,如果用户只能与页面上的2个按钮交互,一个按钮将写入数据库中批准的请求,另一个按钮将写入数据库中被拒绝的请求。 (是的,这是我正在谈论的一种形式,但是所有字段都是只读字段,无法修改,只有我上面提到的带有固定值的2个按钮被发送到db)

– BRoebie
2015年12月4日在7:54

#2 楼

TL; DR如果您的应用接受任何用户输入,请100%地使用准备好的语句。


您似乎有些困惑。首先,请不要使用mysql_*mysql_*函数已过时,不建议使用且不安全。请改用MySQLiPDO。其次,mysql_num_rows与准备好的语句无关,而且不是PDO功能。您可以在运行查询之前先准备语句,而不要在要计算行数时在语句之后。

关于何时准备语句,@ Mike'Pomax'Kamermans在注释中添加了该语句。如果您曾经甚至曾经使用过用户(甚至是所谓的受信任用户)曾经触摸过的任何数据,或者使用任何类型的第三方或第三方应用程序(包括浏览器)生成的数据,请使用准备好的语句。仅当100%的数据经过硬编码或完全由代码生成(例如简单的计数器变量)时,您才能信任它。

例如,您不能信任:


用户名
密码
电子邮件地址
用户注释
电话号码
日期
搜索字符串
浏览器客户端字符串
/>信用卡号
用于上传的文件名
以及用户创建或用户可以操纵的任何其他输入。

您应验证所有这些信息(例如,在将它们放入数据库之前,请先检查电子邮件地址是否确实是电子邮件地址)。但是即使那样,使用准备好的语句仍然是安全的方法。

评论


我明白你的意思。我提到我正在使用mysql_num_rows的原因是因为我看到了这个stackoverflow.com/questions/11305230/…,这似乎毫无意义。如果没有用户数据正在处理,那么mysql_num_rows应该可以,对吗?

– G.SINGH
2014年7月29日在2:42

是;只要确定没有用户数据,例如mytable中的SELECT COUNT(*),就不必使用准备好的语句。不过,就我个人而言,我建议始终使用准备好的语句。当没有用户数据的旧查询被更新并且程序员忘记为新查询使用准备好的语句时,会引入许多安全漏洞。那只是我的意见。

– Elixenide
2014年7月29日在2:57

#3 楼

为此,有两种解决方案-

01-使用预准备语句

为了防止SQL注入,我们将不得不使用称为预定义语句的东西,该语句使用绑定参数。预处理语句不会将变量与SQL字符串组合在一起,因此攻击者无法修改SQL语句。预处理语句将变量与已编译的SQL语句结合在一起,这意味着SQL和变量是分开发送的,并且变量仅被解释为字符串,而不是SQL语句的一部分。

02-预处理语句使用mySQLi。

使用以下步骤中的方法,您将不需要使用任何其他SQL注入过滤技术,例如mysql_real_escape_string()。这是因为使用准备好的语句无法进行常规的SQL注入。

例如-

$name = $_GET['username'];

if ($stmt = $mysqli->prepare("SELECT password FROM tbl_users WHERE name=?")) {

    // Bind a variable to the parameter as a string. 
    $stmt->bind_param("s", $name);

    // Execute the statement.
    $stmt->execute();

    // Get the variables from the query.
    $stmt->bind_result($pass);

    // Fetch the data.
    $stmt->fetch();

    // Display the data.
    printf("Password for user %s is %s\n", $name, $pass);

    // Close the prepared statement.
    $stmt->close();

}


您可以找到有关此格式的更多信息-http://www.wikihow.com/Prevent-SQL-Injection-in-PHP

#4 楼

Mysql_*已被弃用,因此最好改用mysqli_*PDO

防止SQL注入(mysql):-如何防止PHP中的SQL注入?。

和准备好的语句(这些是独立于任何参数发送到数据库服务器并由数据库服务器解析的SQL语句。)在每个用户生成的查询数据上使用。

就像发布数据一样,通过查询将匹配/获取记录到数据库。因此意味着当您使用表单数据触发查询时。