2017-01-25 19 views
2

Я хочу, чтобы пользователь мог выбрать, какие результаты заказа будут отображаться, например. по возрасту), и я не хочу сортировать их после получения их из базы данных.Как мне параметризовать имена столбцов в pysqlite, чтобы избежать SQL Injection

Очевидно, что если пользователь может указать ввод, который влияет на команды SQL, его необходимо очистить, и я бы обычно использовал параметризацию, но pysqlite, похоже, игнорирует параметры для чего-либо, кроме значений.

Пример кода ниже показывает, что параметризация не работает для ORDER BY, а также обходным путем с использованием форматирования строк, но это уязвимо для SQL-инъекции.

Рекомендованное решение, позволяющее пользователю вводить данные о влиянии порядка сортировки, не подвергая уязвимости SQLi? Должен ли я использовать форматирование строк и проверять каждый пользовательский ввод вручную?

#!/user/bin/env python3 

import sqlite3 

con = sqlite3.connect(':memory:') 
cur = con.cursor() 
cur.execute('CREATE TABLE test (name, age)') 
cur.execute('INSERT INTO test VALUES (:name, :age)', {'name': 'Aaron', 'age': 75}) 
cur.execute('INSERT INTO test VALUES (:name, :age)', {'name': 'Zebedee', 'age': 5}) 

cur.execute('SELECT * FROM test ORDER BY age ASC') 
results = cur.fetchall() 
print('\nGood, but hard coded:\n', results) 
# Good, but hard coded: 
# [('Zebedee', 5), ('Aaron', 75)] 

cur.execute('SELECT * FROM test ORDER BY :order_by ASC', {'order_by': 'age'}) 
results = cur.fetchall() 
print('\norder_by parameter ignored:\n', results) 
# order_by parameter ignored: 
# [('Aaron', 75), ('Zebedee', 5)] 

cur.execute('SELECT * FROM test ORDER BY {order_by} ASC'.format(order_by='age')) 
results = cur.fetchall() 
print('\nRight order, but vulnerable to SQL injection:\n', results) 
# Right order, but vulnerable to SQL injection: 
# [('Zebedee', 5), ('Aaron', 75)] 

con.close() 
+0

BTW, я просто попытался с помощью SQLI с этим входом ' 'возраст; DROP TABLE test; - «для третьей команды SQL, и pysqlite поднял исключение, говорящее« sqlite3.Warning: вы можете выполнять только одно заявление за раз ». Поэтому, возможно, я не должен беспокоиться? Мне все еще кажется, что использование форматирования строк опасно, хотя ... – Grezzo

+0

Может ли пользователь каким-либо образом повлиять на фактическое содержимое строки? (В вопросе вы используете постоянную строку '' age'', что не имеет смысла.) –

+0

Это происходит из запроса http. Если они используют правильный клиент (веб-страницу), это должно быть любое из шести имен столбцов, но если кто-то решит быть злым, это может быть все, что они выбирают. – Grezzo

ответ

3

Параметры SQL используются только для значений; все остальное может изменить смысл запроса. (Например, ORDER BY password может оставить подсказки, как мог ORDER BY (SELECT ... FROM OtherTable ...).)

Для того, чтобы имя столбца от клиента действительна, вы можете использовать белый список:

if order_by not in ['name', 'age']: 
    raise ... 
execute('... ORDER BY {}'.format(order_by)) 

Но это все еще плохая идея для интеграции этой строки в запрос, потому что проверка и фактическая таблица могут выйти из синхронизации, или вы можете забыть чек. Лучше возвращать индекс столбца от клиента, так что фактическая строки вы используете всегда самостоятельно, и любые ошибки могут быть легко обнаружены в ходе обычного тестирования:

order_by = ['name', 'age'][order_index] 
execute('... ORDER BY {}'.format(order_by)) 
+0

Используйте константу, чтобы указать значения имен 'order_index' (например,' NAME_COLUMN = 0'). Таким образом, вы можете легко добавить больше столбцов или переместить их, и вы сможете увидеть, какой заказ вы хотите. –

+0

Также обратите внимание, что вы можете легко создавать более сложные порядки, такие как «имя ASC, возраст DESC», предоставляя им свой собственный индекс. –

+0

Отличный ответ, особенно пример заказа по столбцам может дать подсказки пароля. Благодарю. Тогда есть белый список. – Grezzo