3 Вопросы, касающиеся Python и SQLite - PullRequest
2 голосов
/ 06 ноября 2010

Хорошо, я создаю функции для использования с игровым сервером. Этот сервер использует плагины. У меня есть эти функции, которые используют базу данных sqlite вместе с apsw для извлечения элементов, хранящихся в другой функции. У меня есть 3 вопроса по этому вопросу.

Вопрос первый: я продолжаю получать сообщение об ошибке «SQLError: near»? »: Синтаксическая ошибка« Поскольку в моем утверждении многократное выражение?

Вопрос второй: я знаю о SQL-инъекциях, но эти функции получают информацию только от исполнителя сценария, и единственное, что он может повредить, это его собственные. Тем не менее, есть ли простой способ сделать этот sql-инъекцией доказательство?

Вопрос третий: есть ли способ сделать эту функцию более эффективной?

Вот функция: РЕДАКТИРОВАТЬ: Вот как это выглядит сейчас:

def readdb(self,entry,column,returncolumn = "id,matbefore,matafter,name,date"):
    self.memwrite
    if isinstance(entry, int) or isinstance(entry, str):
        statement = 'SELECT {0} FROM main WHERE {1} IN {2}'.format(returncolumn,column,entry)
        self.memcursor.execute(statement)
        blockinfo = self.memcursor.fetchall()
        return(blockinfo)
    if isinstance(entry, tuple) or isinstance(entry, list):
        statement = '''SELECT {0} FROM main WHERE {1} IN (%s)'''.format(returncolumn,column)
        self.memcursor.execute(statement % ("?," * len(entry))[:-1], entry)
        blockinfo = self.memcursor.fetchall()
        return(blockinfo

Ответы [ 2 ]

3 голосов
/ 06 ноября 2010

Это забавно (читайте дальше, чтобы узнать почему).

Первое утверждение, которое у вас есть, фактически использует механизм привязки значений sqlite3 -модуля (я полагаю, это то, что вы используете). Следовательно, * (который является столбцом по умолчанию) экранируется, что делает оператор недействительным. Это доказательство SQL-инъекции, и ваш собственный код пытается внедрить SQL (видите смешно сейчас?).

Во второй раз вы используете замену строки Pythons для построения строки запроса, которая не является доказательством SQL-инъекции.

0 голосов
/ 20 ноября 2010

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

 cur.execute("select ? ?,?", (1,2,3))
 SQLError: near "?": syntax error

Теперь с именами:

 cur.execute("select :1 :2,:3", (1,2,3))
 SQLError: near ":2": syntax error

Если у вас много привязок, я бы порекомендовал вам переключиться на именованный стиль привязок и передать словарь для самих привязок.

cur.execute("select :artist, :painting, :date", 
  {"artist": "Monster", "painting": "The Duck", "date": "10/10/2010" })

Вы можете использовать привязки только для значений, но не для имен столбцов или таблиц. Есть несколько возможных подходов. Хотя SQLite поддерживает произвольные имена столбцов / таблиц, вы можете потребовать, чтобы они представляли собой только буквенно-цифровой текст ASCII. Если вы хотите быть менее строгим, вам нужно процитировать имена. Используйте квадратные скобки вокруг имени с двойными кавычками и двойные кавычки вокруг имени с квадратными скобками. Имя не может иметь обоих.

Альтернатива всему, что использует механизм авторизации. См. Connection.setauthorizer для API и указатель на пример. Вкратце ваш обратный вызов вызывается с действиями, которые будут предприняты, например, вы можете отклонить все, что будет записано в базу данных.

С точки зрения эффективности, вы можете улучшить ситуацию в зависимости от того, как вызывающий абонент использует результаты. Курсоры очень дешевые. Нет необходимости снова и снова повторять одно и то же, и это может привести к незначительным ошибкам. SQLite получает следующий ряд результатов только тогда, когда вы его запрашиваете. Используя fetchall, вы настаиваете на создании списка всех результатов. Если список может быть большим или вы можете прекратить часть пути, просто верните db.cursor().execute("... query ..."). Затем вызывающая сторона должна использовать вашу функцию для итерации:

for id,matbefore,matafter,name,date in readdb(...):
    ... do something ...

На вашем месте я бы просто отбросил эту функцию readdb, так как она не добавляет никакого значения, и напрямую писал запросы:

for id,foo,bar in db.cursor().execute("select id,foo,bar from .... where ...."):
    ... do something ...

Ваш стиль кодирования означает, что вы довольно плохо знакомы с Python. Я настоятельно рекомендую поискать итераторы и генераторы. Это гораздо более простой стиль кодирования, производящий и потребляющий результаты по мере необходимости.

Кстати, этот SQL создает таблицу с именем нулевой длины и столбцами с двойными кавычками и точками с запятой. SQLite прекрасно работает, но не делайте этого :-) Однако он полезен для тестирования.

create table "" (["], ";");

Раскрытие информации: я автор APSW

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...