MySQL INJECTION解决方案

时间:2010-05-07 09:45:32

标签: mysql sql-injection solution

我一直被MySQL注射困扰,并且正在考虑一种消除这个问题的方法。我想出了下面的内容希望很多人会觉得这很有用。

我能想到的唯一回报就是部分搜索: Jo =>使用类似的%%语句返回“John”。

这是一个php解决方案:

<?php
function safeQ(){
   $search= array('delete','select');//and every keyword...
   $replace= array(base64_encode('delete'),base64_encode('select'));
   foreach($_REQUEST as $k=>$v){
      str_replace($search, $replace, $v);
   }
}
safeQ();

function html($str){
   $search= array(base64_encode('delete'),base64_encode('select'));
   $replace= array('delete','select');//and every keyword...
   str_replace($search, $replace, $str);
}

//example 1
...
...
$result = mysql_fetch_array($query);
echo html($result[0]['field_name']);

//example 2
$select = 'SELECT * FROM $_GET['query'] '; 

//example 3
$insert = 'INSERT INTO .... value( $_GET['query'] )'; 


?>

我知道,我知道您仍然可以使用1=1或任何其他类型的注射进行注射...... 但是我觉得这可以解决你问题的一半,所以执行了正确的mysql查询。

所以我的问题是,如果有人能找到任何退款,请随时在这里发表评论。

只有当你认为这是一个非常有用的解决方案并且没有发现任何重大缺点或者你认为这些都是一个坏主意时,请给出答案......

4 个答案:

答案 0 :(得分:11)

这已在PHP中正确实现:

  

但是,您应该首先阅读 PHP manual entry on SQL injection


要回答您的实际问题,您的方法的主要缺点是:

  1. 不起作用
  2. 为了清楚起见,它不起作用,并且会让你对SQL注入保持开放。
  3. 它还可以防止您输入任何与MySQL关键字冲突的数据。
  4. 如果您要重新发明轮子,我建议您查看预先存在的轮子。

答案 1 :(得分:6)

重新发明轮子并将其重新发明为Wrong Way(TM)。

  • 首先,有参数化查询(可在MySQLi扩展名中用于PHP);如果这不是一个选项,那就是mysql_real_escape_string。这是主要问题 - 在决定自行实施之前检查已有的选项。
  • 其次,你试图在SQL中调用PHP函数,你想要的可能是'SELECT * FROM ' . safeQ($_GET['query'])
  • 第三,你已经打破所有索引并搜索包含你的“恶言”的数据,对性能问题和疯狂的解决方法问好。

编辑:要解决您在评论中提供的示例:

$v="1; DROP tbl;\";DROP tbl" // oh look, an SQL injection attempt!
$s = 'SELECT * FROM tbl WHERE ID='.$v; // SQL injection, no doubt

// if ID is an integer field, make it an integer. Simple, secure, and fast.
$s = 'SELECT * FROM tbl WHERE ID='.(int)$v; 
// $s == 'SELECT * FROM tbl WHERE ID=1' // see PHP manual for explanation of type casting

// if ID is a string field, escape it. Simple, secure, and still plenty fast.
$s = 'SELECT * FROM tbl WHERE ID="'.mysql_real_escape_string($v) . '"';
// $s == 'SELECT * FROM tbl WHERE ID="1; DROP tbl;\";DROP tbl"'; 
// See? No injection, as the quote is *escaped*

答案 2 :(得分:2)

这是一个坏主意。

在每种语言,平台,运行时,引擎,库中都有一个适当的,正确的,可行的SQL注入解决方案,非常适合。

这叫做参数。

不是将值作为文字常量放入SQL中,而是添加参数占位符,然后在查询旁边提供参数值,而不是使用任何格式化技巧将其恢复到SQL中。

尝试通过查看SQL或其中的部分并尝试确定它是否正确而试图“修复”问题的其他解决方案都是低于标准的,并且其中大多数都有其他错误和问题,您无法看到,不知道,并不是真的想拥有。

所以停止在灌木丛周围跳动,并以正确的方式开始。切换到使用参数。

在PHP中,与MySQL交谈,有多种方法,但使用mysqli库:

$stmt = $db->prepare('SELECT * FROM products WHERE id = ?');
$stmt->bind_param('i', $id);
$stmt->execute();
.. bind for results
$stmt->fetch();

如果这里的$ id变量包含不安全的代码,它将使SQL执行崩溃,因为如果id是一个整数,它不能与除了另一个整数之外的任何东西进行比较,如果它是一个字符串,它将被比较您提供的字符串,而不是尝试将字符串作为SQL的一部分执行。

现在,评论提出了一个观点,有时您必须更改SQL,因为您将提供动态排序(即用户选择的排序),或动态过滤(即要应用哪些过滤器)用户)。

在这种情况下,解决方案很简单:不要使用任何用户提供的文本并将其放入SQL 。相反,您需要对常量进行硬编码以将SQL添加到代码中,并让用户选择指导要添加哪些常量的代码,按顺序和位置。

答案 3 :(得分:1)

看,你从错误的角度思考它 虽然很多人都这么做。 根据SQL注入有两个强烈的误解:

  1. 有一些特殊攻击,称为“SQL注入”。
  2. 为了防止它,输入数据必须以某种特殊方式受到威胁。
  3. 他们两个都错了。

    当您遵循SQL语法时,没有“SQL注入”这样的东西。

    去图。

    如果你遵循SQL语法规则(无论如何你必须遵循它,尽管有注射!)你是安全的,只是副作用。

    放入SQL查询的任何字符串数据都必须遵循2条规则:
    1.必须转义字符串中的所有特殊字符 2.字符串必须用引号括起来。

    非文本数据也存在问题。也没什么大不了的 但是如果你觉得它太复杂了,你总是可以去做准备好的陈述 - 它总是安全的,不允许思考。

    虽然查询的非数据部分仍然存在问题。这确实是最危险的部分。唯一的问题是有权被称为“SQL注入” 为避免这种情况,查询的所有动态非数据部分都必须在脚本中进行硬编码。这是唯一可能的方式。