嘿伙计我最近决定将我使用php mysql_query执行的所有当前普通mysql查询切换到PDO样式查询,以提高性能,可移植性和安全性。我对这个数据库交互工具中的任何专家都有一些简单的问题
如果准备好所有陈述,是否会阻止注射? (我在php.net上注意到它写了'但是,如果查询的其他部分是用非转义输入构建的,那么SQL注入仍然可能'我不完全确定这意味着什么)。这是否意味着如果所有变量都通过prepare函数运行它是安全的,如果有些是直接插入那么它不是吗?
目前,我在页面顶部有一个连接,在页面的其余部分执行查询。我更详细地看了一下PDO,并注意到每个涉及连接和关闭该连接的查询都有一个try和catch过程。是否有一种直接的方式来连接然后重新使用该连接而无需尝试所有内容或通过连接,查询和关闭不断重复该过程?
任何人都可以用外行的方式简单解释一下set_exception_handler的用途是什么?
我感谢任何有经验的人提出的建议。
答案 0 :(得分:3)
没有SQL注入预防的灵丹妙药。即使你准备了它,也可能有一个不安全的查询。
$sql = "SELECT * FROM MyTable WHERE id = " . $_GET["id"];
$stmt = $pdo->prepare($sql);
请参阅?准备只需要一个字符串并准备它作为SQL查询。在准备之前,您仍然可以将不安全的内容插入到字符串中。准备只看到一个字符串,它不知道你是字面写的还是字符串的一部分是来自不值得信任的来源。
您可以在SQL查询中使用参数占位符,然后在预准备语句上调用execute()
时,提供动态值。但是,您只能在SQL表达式中使用参数占位符代替文字值 - 查询中的其他类型的动态内容无法参数化。有关SQL注入的示例和许多其他信息,请参阅我的演示文稿SQL Injection Myths and Fallacies。
我没有将每个 PDO调用放在try块中。我编写了一个类来封装我的应用程序的一些逻辑上有凝聚力的部分的数据访问。当我调用该类时,我将调用包装在try块中。如果在该类中可能有许多数据库访问操作中出现任何问题,我会抓住它并处理它。
您可以使用set_exception_handler()
代替catch
块。如果您的应用程序中发生异常,但是您没有抓住它并且它一直向上冒泡,直到它将中止脚本,此函数被调用。想象一下,您的整个PHP脚本位于一个顶级try
块中,并且您声明的代码将位于相应的catch
块中。
我从不使用set_exception_handler()
。函数运行后,您的脚本无论如何都会暂停执行,因此没有机会重新尝试产生异常的操作。它也在顶级范围内运行,因此您将失去异常的上下文。在那一点上你唯一可以做的就是打印异常消息和纾困。我更喜欢处理更接近原点的异常,所以我可以添加一些关于异常上下文的信息,或者在PHP脚本停止之前做一些其他事情。
重新评论:
您不应将mysql_real_escape_string()
用于表名或列名,因为引用标识符的规则与引用文字字符串值的规则不同。只是不要将来自外部或不可信来源的输入插入到SQL查询中。
我在演示文稿中使用关联数组编写了一个代码示例,这样如果用户输入与已知值匹配,它会将其用作关联数组中的键,以查找表(或列)的合法名称。例)。这意味着您不必使用任何转义/引用功能,因为您不会将不受信任的内容插入到SQL查询中。您只需插入在关联数组中预定义的值。
关于例外,我的意思是(高级别):
$domainObject = new MyDomain();
try {
$domainObject->create_report($formInput);
} catch (PDOException $e) {
// Report error politely so the user knows what happened
// and what they can do to fix it.
}
create_report()
内的工作很复杂,可能涉及多个SQL查询,其中任何一个都可能以多种方式出错。您不一定需要为该函数内的每个SQL操作捕获异常,您可以捕获从函数中弹出的任何和所有异常,并在调用create_report()
的代码中在一个地方处理它们
此外,您可能不希望只是向他们发出逐字异常消息,因为他们不知道该怎么做。