Safe alternative to mysql_real_escape_string? (PHP) 安全的mysql_real_escape_string的替代方法?(PHP)
Safe alternative to mysql_real_escape_string? (PHP) 安全的mysql_real_escape_string的替代方法?(PHP)
我将一个变量传递给一个执行查询的函数
MySQL连接仅在函数内部发生,并在函数内部关闭
我希望在将字符串发送到函数之前能够安全地转义它们
我不能使用mysql_real_escape_string,因为它需要一个MySQL连接(该连接仅在函数内部创建)
我知道简单的答案是在函数内部转义字符串,但我不能这样做,因为我需要发送一些转义的和一些非转义的字符串的部分
例如,我需要像这样运行函数:
myquery("'" . escape_me("My string") . "'");
注意,我发送了两个撇号--未转义的,带有转义的字符串内部。因此,我不能在myquery函数的参数中使用mysql_real_escape_string。
我找到了以下代码,建议我可以将其用作mysql_real_escape_string的替代方法:
// 转义字符 function escape_me($value) { $return = ''; for($i = 0; $i < strlen($value); ++$i) { $char = $value[$i]; $ord = ord($char); if($char !== "'" && $char !== "\"" && $char !== '\\' && $ord >= 32 && $ord <= 126) $return .= $char; else $return .= '\\x' . dechex($ord); } return $return; }
我不知道这个函数是否安全,能否防止多字节攻击,但我认为每次查询都需要撤销该函数
例如,输入:
Testing 3's "OK" 转换为 Testing 3x27s x22OKx22 在数据库中
所以我的主要问题是:
您是否知道是否有另一个函数可以作为mysql_real_escape_string的替代方法,可以安全地转义字符?
问题:安全替代mysql_real_escape_string()的方法是什么?
原因:mysql_real_escape_string()函数在处理字符串时可以防止SQL注入攻击,但在某些情况下可能会出现安全问题。为了找到更安全的替代方法,用户提出了这个问题。
解决方法:建议传入一个需要转义的值的数组,并使用sprintf()函数格式化查询语句,同时对每个值进行转义。以下是查询函数的第一部分:
public function querya($query, $args=null){ //检查是否传入了args参数 if($args !== null){ //如果是一个数组... if(is_array($args)){ //...对args数组中的每个值进行转义 foreach($args as $key=>$value){ $args[$key] = mysql_real_escape_string($value); } //将查询语句添加到args数组的开头 array_unshift($args, $query); //使用数组作为sprintf的参数来调用sprintf函数 $query = call_user_func_array("sprintf", $args); } else { //如果args不是一个数组,则是一个字符串(传入的是单个参数) $query = sprintf($query, mysql_real_escape_string($args)); } } //执行查询和其他操作 }
在类似的函数中,我会给%s通配符添加引号,以确保查询中没有未引用的%s。这样做是为了保险起见。由于这个方法只是我自己使用的,所以我通常会这样编写查询语句:$DB->querya("SELECT COLUMN FROM TABLE WHERE VALUE='%s' AND 1=%d",array('test',1));
,并在需要时在查询中的%s周围添加引号。
安全的替代方法是使用预处理语句(prepared statements),预处理语句可以防止SQL注入攻击。可以通过以下代码实现:
function fetchAll(){ $args = func_get_args(); $query = array_shift($args); $stmt = $pdo->prepare($query); $stmt->execute($args); return $stmt->fetchAll(); } $a=$db->fetchAll("SELECT * FROM users WHERE status=? LIMIT ?,?",$status,$start,$num);
如果使用单字节编码或UTF-8编码,就不需要使用`mysql_real_escape_string`函数,`mysql_escape_string`(已弃用)或`addslashes`就足够了。
`mysql_escape_string`函数已经被弃用(而推荐使用`mysql_real_escape_string`),除此之外,其他都是好的建议。连接一次,然后在每个查询之前打开和关闭连接,比每次查询都连接一次更好。
原问题中提到了连接每次调用函数都是一个糟糕的想法,并且指出了良好规划的应用程序不会有这样奇怪的限制。可以使用替换(substitutions)的方法来解决这个问题,如下所示:
myquery("SELECT * FROM table WHERE id = %s","My string");
总结起来,避免使用`mysql_real_escape_string`函数可以通过使用预处理语句或者在单字节编码或UTF-8编码中使用`mysql_escape_string`函数来解决这个问题。并且,为了提高性能,应该在每个查询之前打开连接,而不是每次调用函数都连接一次。