此检查是否可以避免SQL注入?

时间:2018-07-05 08:06:39

标签: sql oracle sql-injection

我需要将where条件从客户端传递到Web服务,该服务在oracle数据库上执行SQL查询。

 const res = await db.execute(`SELECT count(ID) FROM table WHERE ${where}`);

由于where条件可以是完全动态的,因此我不能使用准备好的语句,存储过程或参数。

仅通过以下检查运行where条件就足够了吗?

static isDangerousSql(sql: string): boolean {
    const characters = [ '--', ';'];

    for (const char of characters) {
        if (sql.indexOf(char) > -1) {
            return true;
        }
    }

    return false;
}

1 个答案:

答案 0 :(得分:5)

不,这还不够。

如果${where}是:

EXISTS (
  SELECT 1
  FROM   security_table
  WHERE  userid        = 1234
  AND    password_hash = CHR(65) || CHR(66) || CHR(67) || CHR(68)
)

然后它将:

  1. 通过您的支票;
  2. 确认存在一个名为security_table的表;
  3. 确认该表具有列useridpassword_hash;和
  4. 确认存在一个ID为1234且密码哈希为ABCD的用户

这可用于映射您的整个数据库结构并检查是否存在任何数据。绝对是一个漏洞。


  

一个例子是

WHERE status = 'Active' and ID in (SELECT cell_id FROM alerts WHERE alert_status = 1)

您可以使用查询中列出的有效过滤条件,并使用绑定参数来填充过滤条件,而不是使用动态SQL:

一个稍微复杂的例子是:

SELECT count(ID)
FROM   table t
WHERE  ( :status IS NULL OR status = :status )
AND    (  ( :alert_status IS NULL AND :other_status IS NULL )
       OR EXISTS (
            SELECT 1
            FROM   alerts a
            WHERE  t.id = a.cell_id
            AND    ( :alert_status IS NULL OR alert_status = :alert_status )
            AND    ( :other_status IS NULL OR other_status = :other_status )
       ) )

然后您有一个静态查询,并且可以传入(命名)绑定变量:status:alert_status:other_status

  • 您的用户不需要了解基础表结构。
  • 该代码不容易受到SQL注入的攻击。<​​/ li>
  • 您可以控制他们可以访问哪些数据。
  • 数据库可以缓存静态查询。

如果您不希望使用所有参数进行单个静态查询,则可以从中间层的固定代码段组件中构建过滤器。

一些伪代码:

sql             = "SELECT count(ID) FROM table";
filters         = [];
bind_parameters = [];
if ( [ 'Active', 'Inactive' ].indexOf( user_input.status ) > -1 )
{
  filters.push( "status = ?" )
  bind_parameters.push( user_input.status );
}
if ( user_input.active_status == 0 || user_input.active_status == 1 )
{
  filters.push( "id IN ( SELECT cell_id FROM alerts WHERE alert_status = ?)" );
  bind_parameters.push( user_input.active_status );
}
if ( filters.length > 0 )
{
  sql = sql + " WHERE " + filters.join( " AND " );
}
db.setSQL( sql );
for ( i = 0; i < bind_parameters.length; i++ )
{
  db.setBindParameter( i, bind_parameters[i] );
}
const res = await db.executeQuery();

(上面的伪代码用于指示从固定代码段在中间层动态构建查询的概念,并且不考虑实现细节,例如设置绑定参数的数据类型以及可能的许多其他事情) -谨慎使用该想法,并在将其投入生产之前验证实现的安全性。)