安全地实施"可配置"连接系统

And*_*ong 5 php mysql pdo join

背景

您好,我正在开发PHP和MySQL的实验/教育工具.我是SQL的新手,但我想从一开始就以正确的方式做事.我正在为所有变量替换使用PDO预处理语句,并且可以在任何地方进行反向操作(因此,据我所知,它不能移植到非MySQL数据库).关于我的问题,我有一个关于如何前进的想法,但是我需要花费几个小时来实现(我甚至对SQL的语法都是新的),所以同时我认为我先创建一个问题万一有人可以喊叫,"这不是办法!" 并节省我几个小时的努力.

问题

我想创建一个用户可以从下拉菜单中选择的界面:

  1. 一张桌子A,
  2. 该表上的,例如一个或多个字段A.xA.y,
  3. 一张桌子B,
  4. 该表上的,例如一个或多个字段B.zB.y,

在提交代码将执行一个内部联接,每个字段分别匹配,例如A.x = B.z,A.y = B.y等等,并返回所有匹配的行.

我的计划只是生成一个INNER JOINSQL语句,循环遍历字段并插入占位符(?),绑定相应的参数,最后执行语句.

有更简单的方法吗?有没有更好的方法呢?这会以某种方式被利用吗?

非常感谢,提前.如果没有人在我结束时做出回应(可疑),我会发布我的解决方案.

杂项.

假设我将验证

  1. 用户在A和之间选择相同数量的字段B,
  2. 字段和表存在,
  3. 等等

并且字段名称不必相同:它们将按顺序匹配.(请指出我可能不知道的任何其他细节!)

最终,目标是将这些选择本身保存在"设置"表中.实际上,用户创建他们希望每次回来时都能看到的"视图".

egg*_*yal 2

你做得太正确了,以至于我真的感到内疚指出你做错了!:)

您只能使用准备好的语句来参数化字段值,而不能使用 SQL 标识符,例如列名或表名。因此,您将无法通过准备好的语句参数将等传递到您的A.x条件中:您必须做一些感觉非常错误的事情,并将它们直接连接到您的 SQL 字符串中。B.zJOIN

然而,一切并没有失去。按照一些模糊的偏好顺序,您可以:

  1. 向用户提供一个选项列表,您随后可以从中重新组装 SQL:

    <select name="join_a">
      <option value="1">x</option>
      <option value="2">y</option>
    </select>
    <select name="join_b">
      <option value="1">z</option>
      <option value="2">y</option>
    </select>
    
    Run Code Online (Sandbox Code Playgroud)

    然后你的表单处理程序:

    switch ($_POST['join_a']) {
      case 1:  $acol = 'x'; break;
      case 2:  $acol = 'y'; break;
      default: die('Invalid input');
    }
    switch ($_POST['join_b']) {
      case 1:  $bcol = 'z'; break;
      case 2:  $bcol = 'y'; break;
      default: die('Invalid input');
    }
    
    $sql .= "FROM A JOIN B ON A.$acol = B.$bcol";
    
    Run Code Online (Sandbox Code Playgroud)

    这种方法的优点是,如果不损害 PHP(在这种情况下,您将面临比 SQL 注入更大的担忧),任意 SQL 绝对无法进入您的 RDBMS。

  2. 确保用户输入与预期值之一匹配:

    <select name="join_a">
      <option>x</option>
      <option>y</option>
    </select>
    <select name="join_b">
      <option>z</option>
      <option>y</option>
    </select>
    
    Run Code Online (Sandbox Code Playgroud)

    然后你的表单处理程序:

    if (!in_array($_POST['join_a'], ['x', 'y'])
     or !in_array($_POST['join_b'], ['z', 'y']))
       die('Invalid input');
    
    $sql .= "FROM A JOIN B ON A.$_POST[join_a] = B.$_POST[join_b]";
    
    Run Code Online (Sandbox Code Playgroud)

    这种方法依赖于 PHP 的in_array安全功能(并且还向用户公开您的基础列名称,但考虑到您的应用程序,我怀疑这是一个问题)。

  3. 执行一些输入清理,例如:

    mb_regex_encoding($charset); // charset of database connection
    $sql .= 'FROM A JOIN B ON A.`' . mb_ereg_replace('`', '``', $_POST['join_a']) . '`'
                        . ' = B.`' . mb_ereg_replace('`', '``', $_POST['join_b']) . '`'
    
    Run Code Online (Sandbox Code Playgroud)

    虽然我们在这里引用用户输入并替换用户逃避该引用的任何尝试,但这种方法可能充满各种缺陷和漏洞(在 PHPmb_ereg_replace函数或 MySQL 对引用标识符中特制字符串的处理中)。

    如果可能的话,最好使用上述方法之一来避免将用户定义的字符串完全插入到 SQL 中。