Нет, этого недостаточно.
Если ${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.
- Вы можете контролировать, к каким данным они могут получить доступ.
- База данных может кэшировать статический запрос.
Если вы не хотите иметь один статический запрос со всеми параметрами, тогда вы можете построить фильтры из фиксированных компонентов сниппета на среднем уровне.
Какой-то псевдокод:
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();
(Вышеприведенный псевдокод указывает на концепцию динамического построения запроса на среднем уровне из фиксированных фрагментов и не учитывает детали реализации, такие как установка типа данных параметров связывания и, возможно, многие другие вещи. - используйте идею с осторожностью и проверьте безопасность своей реализации, прежде чем запускать ее в производство.)