Предотвращение внедрения SQL, когда запросы имеют динамически сгенерированные / списки параметров переменной длины

#python #mysql #python-3.x #sql-injection #pymysql

#python #mysql #python-3.x #sql-инъекция #pymysql

Вопрос:

Прошу прощения за плохое название, но я часами искал в Интернете, но ничего не смог найти.

Подумайте о пользовательском поиске, выполняемом с текстом «это хорошо». Я хочу разделить текст пробелами и выполнить SQL-запрос с несколькими «или… например, «зависит от количества слов. Их может быть несколько. Я пробовал;

 sub_query ""
search = "this is good"
split_by_space = search.split(" ")
for word in split_by_space:
    sub_query = sub_query   "content like '%{}%' or".format(word) #---> THIS IS NOT ESCAPED
sub_query = sub_query[0:-3] #---> to remove last ' or'
cursor.execute("select content from posts where %s",(sub_query))
 

Это неправильный способ предотвращения SQL-инъекции или подготовленного оператора.

Итак, как сделать подготовленный оператор в Python / pymysql, если я хочу разделить слова пробелами и выполнить поиск по каждому отдельному слову?

Комментарии:

1. Это, вероятно, одно из лучших руководств по предотвращению внедрения SQL. realpython.com/prevent-python-sql-injection

2. Такие инструменты, как конструктор запросов SQLAlchemy (который можно использовать полностью независимо от ORM в том же пакете), сделают это за вас автоматически (динамически генерируя запрос с заполнителями и внеполосный набор значений для этих заполнителей). Я бы посоветовал не изобретать велосипед, тем более что драйверы баз данных для DB-API Python могут использовать один из нескольких интерфейсов, поэтому для обеспечения совместимости требуется поддержка всех доступных соглашений; SQLAlchemy уже поддерживает весь набор, поэтому его использование значительно упрощает переключение с MySQL на PostgreSQL / Oracle / что угодно.

Ответ №1:

Вот один из способов сделать это безопасно:

 search = "this is good"
split_by_space = search.split(" ")
terms = []
params = []
for word in split_by_space:
    terms.append("content like %s")
    params.append("%%{}%%".format(word)) 
query = "select content from posts where %s".format(" OR ".join(terms))
cursor.execute(query, params)
 

Но вы обнаружите, что использование LIKE с подстановочными знаками не работает должным образом. Использование LIKE может привести к тому, что запрос займет в тысячи раз больше времени, чем использование полнотекстового индекса (в зависимости от количества строк в таблице). Смотрите Мою презентацию с полнотекстовым поиском.