使用动态查询防止SQL注入

时间:2014-09-24 14:34:13

标签: java jdbc sql-injection

因此,在where子句参数

中使用时,始终使用PreparedStatement来避免注入
select * from user where id = ? and group = ?

我需要将列设置为在运行时选择

select ? from user where id = ? and group = ?

甚至where子句

中的列名
select ? from user where ? = ? 

PreparedStatement不支持此功能。还有谁支持这个?

更新

  • 我更改了标题以取消PreparedStatement的范围。
  • 我将PreparedStatement作为可以处理“动态”查询的库类的示例 避免在where值上使用sql-injection。

我的用例:我有一个通用的REST API到(ny)数据库。 用户可以请求

http://server/g/db100/users/300/phone 

那被翻译成

select phone from users where id = 300

phone可以是任何其他列名称(如果列不存在,则服务器响应404等)。所以我没有动态生成查询,并想在自己做之前知道是否有一个lib。

2 个答案:

答案 0 :(得分:1)

你不能做那个预备语句的占位符是列值而不是表名。

使用String-concatenation,如

String tablename="xyz";

String query= "select "+tablename+" from user where id = ? and group = ?";

答案 1 :(得分:0)

这样的事情应该适用于您的目的(为博客构建动态查询的示例):

    $DB = new PDO('mysql:host='.DBHOST.';port='.DBPORT.';dbname='.DBNAME, DBUSER, DBPASSWORD);
    if (!$DB) {
        throw new Exception('Could not connect to database');
    }

    $sql = '';

    $select = array(); //which fields to select
    $join = array(); //any additional tables to join
    $where = array(); //'where' clause
    $params = array(); //parameters to add to PDO

    //regardless of parameters, select the id
    array_push($select, "posts.id");

    array_push($join, "blog_posts posts");

    array_push($where, "1=1");
    array_push($where, "published_date <= NOW()");

    //some sort of dynamic query - if we're specifying a search to filter by
    if (isset($search) && $search !== '') {
        $searchparts = explode(' ', $search);

        $searchsql = array();
        foreach($searchparts as $key=>$value) {
            array_push($searchsql, "(posts.title LIKE ? OR posts.content LIKE ?)");

            array_push($params, '%'.$value.'%');
            array_push($params, '%'.$value.'%');
        }

        array_push($where, '('.implode(' OR ', $searchsql).')');
    }

    //generate SQL query
    $sql .= 'SELECT '.implode(', ', $select).' FROM '.implode(' LEFT JOIN ', $join).' WHERE '.implode(' AND ', $where) . ' ORDER BY published DESC';

    $prepared = $DB->prepare($sql);
    $list = $prepared->execute($params);

    if ($list) {
        while ($row = $prepared->fetch(PDO::FETCH_ASSOC)) {
            //do something with the data
        }
    }

另一种选择是将列名称(Java)基本列入白名单:

if (column.equals("phone")) {
    sql += "phone";
} else if (column.equals("computer")) {
    sql += "computer";
}

这样你实际上并没有接受用户输入(虽然它实际上并不重要,因为你已经确认column正好是“phone”),并且只是在构建SQL时某些条件,而不仅仅是任何输入。