我需要将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;
}
答案 0 :(得分:5)
不,这还不够。
如果${where}
是:
EXISTS (
SELECT 1
FROM security_table
WHERE userid = 1234
AND password_hash = CHR(65) || CHR(66) || CHR(67) || CHR(68)
)
然后它将:
security_table
的表; userid
和password_hash
;和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 = "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();
(上面的伪代码用于指示从固定代码段在中间层动态构建查询的概念,并且不考虑实现细节,例如设置绑定参数的数据类型以及可能的许多其他事情) -谨慎使用该想法,并在将其投入生产之前验证实现的安全性。)