我一直在做的简单连接mysql_connect
,mysql_pconnect
:
$db = mysql_pconnect('*host*', '*user*', '*pass*');
if (!$db) {
echo("<strong>Error:</strong> Could not connect to the database!");
exit;
}
mysql_select_db('*database*');
虽然使用这个我一直使用的简单的方法,使查询之前逃脱的任何数据,不管是INSERT
,SELECT
,UPDATE
或者DELETE
通过使用mysql_real_escape_string
$name = $_POST['name'];
$name = mysql_real_escape_string($name);
$sql = mysql_query("SELECT * FROM `users` WHERE (`name` = '$name')") or die(mysql_error());
现在我知道这在一定程度上是安全的!
它逃脱了危险人物;但是,它仍然容易受到其他攻击的攻击,这些攻击可能包含安全字符,但可能有害于显示数据或在某些情况下恶意修改或删除数据。
因此,我进行了一些搜索,以了解有关PDO,MySQLi和准备好的语句的信息。是的,我可能迟到了游戏,但是我读了很多很多教程(tizag,W3C,博客,Google搜索),但没有一个提到这些。关于原因,这似乎很奇怪,因为逃避用户输入确实是不安全的,至少可以说不是一种好习惯。是的,我知道您可以使用Regex来解决它,但是,我很确定那还不够吗?
据我了解,当变量由用户输入指定时,使用PDO
/预处理语句是从数据库存储和检索数据的更安全的方法。唯一的麻烦是,切换(特别是在以我以前的编码方式/习惯非常困住之后)有点困难。
现在我知道使用PDO连接到数据库
$hostname = '*host*';
$username = '*user*';
$password = '*pass*';
$database = '*database*'
$dbh = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
if ($dbh) {
echo 'Connected to database';
} else {
echo 'Could not connect to database';
}
现在,函数名是不同的,因此将不再我mysql_query
,mysql_fetch_array
,mysql_num_rows
等工作。因此,我必须阅读/记住大量新内容,但这是我感到困惑的地方。
如果我想从注册/注册表格中插入数据,我将如何去做,但主要是如何安全地去做呢?我假设这是准备好的语句出现的地方,但是通过使用它们,这消除了使用诸如之类的东西的需要mysql_real_escape_string
。我知道这mysql_real_escape_string
要求您通过mysql_connect
/
连接到数据库,mysql_pconnect
所以现在我们既不使用它,也不会产生错误吗?
我也看到了采用PDO方法的不同方法,例如,我已经看到了,:variable
并且?
我认为这被称为占位符(抱歉,如果那是错误的话)。
但是我认为这大致是应该从数据库中获取用户的想法。
$user_id = $_GET['id']; // For example from a URL query string
$stmt = $dbh->prepare("SELECT * FROM `users` WHERE `id` = :user_id");
$stmt->bindParam(':user_id', $user_id, PDO::PARAM_INT);
但是,接下来我会停留在一些事情上,如果变量不是数字,而是文本字符串,那么PDO:PARAM_STR
如果我没有记错的话,必须给定一个长度。但是,如果不确定用户输入的数据所给出的值,则该长度如何设置呢?无论哪种方式,据我所知显示您随后要做的数据
$stmt->execute();
$result = $stmt->fetchAll();
// Either
foreach($result as $row) {
echo $row['user_id'].'<br />';
echo $row['user_name'].'<br />';
echo $row['user_email'];
}
// Or
foreach($result as $row) {
$user_id = $row['user_id'];
$user_name = $row['user_name'];
$user_email = $row['user_email'];
}
echo("".$user_id."<br />".$user_name."<br />".$user_email."");
现在,这一切安全吗?
如果我是对的,则插入数据是否会相同,例如:
$username = $_POST['username'];
$email = $_POST['email'];
$stmt = $dbh->prepare("INSERT INTO `users` (username, email)
VALUES (:username, :email)");
$stmt->bindParam(':username, $username, PDO::PARAM_STR, ?_LENGTH_?);
$stmt->bindParam(':email, $email, PDO::PARAM_STR, ?_LENGTH_?);
$stmt->execute();
那行得通吗,那也安全吗?如果是正确的话,我会为值多少钱?_LENGTH_?
?我把这完全弄错了吗?
更新
到目前为止,我的回复非常有帮助,不能谢谢你们!每个人都可以通过+1使我睁开眼睛,看到有些不同。选择最佳答案很困难,但我认为Shrapnel上校应有尽有,因为几乎所有内容都已覆盖,甚至使用我不知道的自定义库进入其他阵列!
但是感谢大家:)
感谢您提出有趣的问题。干得好:
它逃脱了危险人物,
您的概念完全 错误。
实际上“危险人物”是神话,没有神话。和mysql_real_escape_string转义,但只是一个 字符串定界符
。从这个定义中,您可以得出它的局限性-仅适用于 string 。
但是,它仍然容易受到其他攻击的攻击,这些攻击可能包含安全字符,但可能有害于显示数据或在某些情况下恶意修改或删除数据。
您在这里混合了所有内容。
说到数据库,
*
至于显示数据,我认为它在与PDO有关的问题中是 题外话 ,因为 PDO也与显示数据无关。
转义用户输入
^^^另一个需要注意的错觉!
用户输入与转义绝对无关 。从前一个定义中可以了解到,您必须转义字符串,而不是“用户输入”。因此,再次:
明白了吗?
现在,我希望您了解转义的局限性以及“危险人物”的误解。
据我了解,使用PDO /预备语句更安全
并不是的。
实际上,我们可以动态添加 四个 不同的查询部分:
因此,您可以看到转义仅涵盖一个问题。(但是,当然,如果将数字视为字符串(用引号引起来),则 在适用 时也可以使其安全)
而准备好的语句涵盖了-嗯-全部2个问题!很大;-)
对于其他两个问题,请参阅我的早期答案:在PHP中,在向数据库提交字符串时,我应该使用htmlspecialchars()还是使用正则表达式来处理非法字符?
现在,函数名称有所不同,因此我的mysql_query,mysql_fetch_array,mysql_num_rows等不再起作用。
那是 PHP 用户的 另一种 严重的幻想 , 一种自然灾害,一场灾难:
即使使用旧的mysql驱动程序, 也永远不要 在其代码中 使用裸露的API函数
!必须将它们放在某种库函数中以供日常使用!(这并不是一个魔术,只是为了使代码更短,更少重复,防错,更一致和可读性更高)。
PDO也是如此!
现在再次提出您的问题。
但是通过使用它们是否可以消除使用mysql_real_escape_string之类的东西的需要?
是。
但是我认为这大致是应该从数据库中获取用户的想法。
不是要获取,而是 要向查询添加任何数据 !
如果我没记错的话,你必须在PDO:PARAM_STR之后给出一个长度
您可以,但不必。
现在,这一切安全吗?
在数据库安全方面,此代码中没有弱点。没什么要固定的。
为了确保显示安全-只需在该网站上搜索XSS
关键字即可。
希望我对此事有所了解。
顺便说一句,对于长插入,您可以使用我有一天写的函数,使用PDO插入/更新帮助器函数
但是,我目前不使用准备好的语句,因为我喜欢使用自制的占位符,而不要使用上面提到 的库 。因此,要对付下面的riha发布的代码,该代码将短于这两行:
$sql = 'SELECT * FROM `users` WHERE `name`=?s AND `type`=?s AND `active`=?i';
$data = $db->getRow($sql,$_GET['name'],'admin',1);
但是,当然,您也可以使用准备好的语句使用相同的代码。
* (yes I am aware of the Schiflett's scaring tales)
问题内容: 今天有人告诉我,我确实应该在应用程序中使用PDO和准备好的语句。在我了解好处的同时,我也在努力了解如何将其实现到我的工作流程中。除了它使代码更简洁外,我是否应该有一个特定的数据库类来容纳所有准备好的语句,还是应该在每次运行查询时都创建一个?我发现很难理解何时应使用标准PDO查询以及何时应使用准备好的语句。任何示例,技巧或教程链接将不胜感激。 问题答案: pdo :: prepare()
问题内容: 我刚刚开始做我的第一个项目(很有趣)。我正在学习PHP和MySQL,并且已经完成了我的第一个正常工作的应用程序。它可以工作,但是我现在正在学习如何保护应用程序的安全,从而防止SQL注入。我大约有50多个PHP文件来管理与MySQL数据库的交互。它们看起来都是这样的: 这是我在整个应用程序中用于向数据库读写数据的格式。如果我需要将它们更改为准备好的语句,而不是在其中插入任何信息,而只是在
我犯了什么错?
问题内容: 在PDO :: Prepare页上指出: “并且通过消除对参数的手动引用来帮助防止SQL注入攻击” 知道这一点,是否有一个像mysql_real_escape_string()这样的PHP函数可以照顾到PDO的转义?还是PDO会为我做好一切转义? 编辑 我现在意识到我问了一个错误的问题。我的问题确实是,“ PDO会为我做什么?” 我现在通过这些答案意识到,它实际上仅消除了对引号进行转义
问题内容: 在将HQL转换为SQL时,Hibernate在JDBC内部使用PreparedStatement。HQL中的内联参数如何处理? 例: 将状态“解析”并用作SQL中的参数,或者将其作为内联参数发送。 我的观点背后的原因是“最佳做法”,以及针对重复调用的查询性能 问题答案: 它被内联发送。当是客户端控制的值时,您绝对不希望这样做。 而是将其参数化: 也可以看看: OWASP-hiberna