Безопасно ли выполнять такой запрос SQL в Python, используя MySQLdb? - PullRequest
4 голосов
/ 08 февраля 2012

Я заметил, что большинство источников говорят, что наилучшая практика выполнения операторов SQL в Python выглядит примерно так:

cursor.execute( 'select * from coworkers where name = :1 and clue > :2', [ name, clue_threshold ] )

В других источниках говорится

cursor.execute( "select * from coworkers where name = %s and clue > %s", ( name, clue_threshold ) )

, что я думаю, очень похоже.

Во всяком случае, я так и делал, создавая словарь и сохраняя значения. Например, начальный словарь biz_info выглядит так:

biz_info = {
    'business'     : None,
    'name'         : None,
    'neighborhood' : None,
    'address'      : None,
    'city'         : None,
    'state'        : None,
    'zip_code'     : None,
    'latitude'     : None,
    'longitude'    : None,
    'phone'        : None,
    'url'          : None,
    'yelp_url'     : None,
}

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

execute_sql( cur, "insert into " + TABLE_BIZ_NAME + """ values (
                   NULL,
                   %(name)s,
                   %(neighborhood)s,
                   %(address)s,
                   %(city)s,
                   %(state)s,
                   %(zip_code)s,
                   %(latitude)s,
                   %(longitude)s,
                   %(phone)s,
                   %(url)s,
                   %(yelp_url)s,
                   NULL
                   )"""
                   , biz_info )

Это безопасно против инъекций sql? Я хочу использовать словари для хранения информации, потому что ими легче управлять.

Если честно, я даже не совсем уверен, какая разница между использованием %, ,, %s, %d и %()s означает в параметризованных запросах. В основном все, что я знаю, это , а не , чтобы использовать

cursor.execute( "select * from coworkers where name = '%s' and clue > %d" % ( name, clue_threshold ) )

Ответы [ 2 ]

3 голосов
/ 08 февраля 2012

Способ передачи параметров в командные строки sql зависит от базы данных (например, sqlite использует ?).

Согласно документации MySQLdb , вы можете использовать *Параметр 1006 * для установки предпочтительного способа форматирования строки (format или pyformat).

Первый пример в вашем вопросе не поддерживается.В любом случае, я бы сказал, что пока вы не отформатируете всю строку, как в предыдущем примере, вы в безопасности, поскольку можно предположить, что параметры запроса будут правильно экранированы.

1 голос
/ 08 февраля 2012

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

cursor.execute \
  (
        "insert into "
    +
        TABLE_BIZ_NAME
    +
        "("
    +
        ", ".join(biz_info.keys())
    +
        ") values ("
    +
        ", ".join(("%s",) * len(biz_info))
    +
        ")",
    biz_info.values()
  )

Таким образом, имена полей должны быть указаны только один раз при создании dict biz_info. И любые будущие изменения нужно только, чтобы они там обновлялись.

...