Python SQLite3 SQL Injection Vulnerable Code

Я знаю, что нижеприведенные фрагменты кода уязвимы для SQL Injection из-за .format, но я не знаю почему. Кто-нибудь понимает, почему этот код уязвим и где я начну его исправлять? Я знаю, что эти фрагменты кода оставляют поля ввода открытыми для выполнения других вредоносных команд через SQL Injection, но не знают, почему

cursor.execute("insert into user(username, password)" " values('{0}', '{1}')".format(username, password)) handle[0].execute("insert into auditlog(userid, event)" " values({0}, '{1}')".format(handle[2],event)) audit((cursor, connection, 0), "registeration error for {0}”.format(username)) sql="""insert into activitylog(userid, activity, start, stop) values({0}, '{1}', '{2}', '{3}') """.format(handle[2], activity, start, stop) 

Из документов :

Обычно ваши операции SQL должны использовать значения из переменных Python. Вы не должны собирать свой запрос с помощью строковых операций Python, потому что это небезопасно; это делает вашу программу уязвимой для атаки SQL-инъекции (см. http://xkcd.com/327/ для юмористического примера того, что может пойти не так).

Вместо этого используйте замену параметров DB-API. Положил ? как местозаполнитель везде, где вы хотите использовать значение, а затем предоставить кортеж значений в качестве второго аргумента методу execute () курсора. (Другие модули базы данных могут использовать другой заполнитель, например% s или: 1). Например:

 # Never do this -- insecure! symbol = 'RHAT' c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol) # Do this instead t = ('RHAT',) c.execute('SELECT * FROM stocks WHERE symbol=?', t) print c.fetchone() 

Пример внедрения SQL с использованием вашего первого оператора SQL:

 cursor.execute("insert into user(username, password) values('{0}', '{1}')".format(username, password)) 

Если username и password являются "blah" результирующий оператор SQL:

 insert into user(username, password) values('blah', 'blah') 

и нет никаких проблем с этим конкретным утверждением.

Однако, если пользователь может ввести значение password , возможно, из HTML-формы, из:

 blah'); drop table user; -- 

результирующий оператор SQL будет выглядеть следующим образом:

 insert into user(username, password) values('blah', 'blah'); drop table user; -- 

который фактически представляет собой 3 оператора, разделенных точкой с запятой: вставка, таблица перетаскивания, а затем комментарий. Некоторые базы данных, например Postgres, будут выполнять все эти инструкции, что приводит к удалению таблицы пользователя. Однако, экспериментируя с SQLite, похоже, что SQLite не разрешает выполнение нескольких операторов одновременно. Тем не менее, могут быть другие способы ввода SQL. OWASP имеет хорошую ссылку на эту тему.

Исправить это легко, используйте параметризованные запросы, подобные этому:

 cursor.execute("insert into user(username, password) values(?, ?)", (username, password)) 

Заполнители добавляются в запрос с помощью ? и механизм db будет правильно избегать этих значений, чтобы избежать инъекций SQL. Результирующий запрос будет выглядеть следующим образом:

 insert into user(username, password) values('blah', 'blah''); drop table users; --') 

где завершение ' в 'blah\'' было надлежащим образом экранировано. Значение

 blah'); drop table users; -- 

будет присутствовать в поле пароля для вставленной записи.

Всякий раз, когда вы создаете операторы SQL, используя строковые операции и данные, предоставленные внешним пользователем, вы открываете до двух видов уязвимостей:

  1. Вредоносные намерения, в которых пользователь вводит значение, используя некоторую комбинацию символов разделителя строк, символов комментариев и операторов SQL UPDATE или DELETE, которые будут иметь негативное влияние на вашу базу данных (см. Ответ mhawke).
  2. Невиновное намерение, в котором пользователь вводит законный текст, но содержит символы, которые ваша программа не ожидает. Примером может служить пользователь с именем O'Reilly . Когда это интерполировано в строку, запасной апостроф сделает результирующий SQL недействительным.