Python MySQLDBIN句で使用するためのリストの内破


84

リストを文字列にマップする方法を知っています:

foostring = ",".join( map(str, list_of_ids) )

そして、私は以下を使用してその文字列をIN句に入れることができることを知っています:

cursor.execute("DELETE FROM foo.bar WHERE baz IN ('%s')" % (foostring))

私が必要としているのは、MySQLDBを使用して同じことを安全に(SQLインジェクションを回避して)達成することです。上記の例では、foostringは実行する引数として渡されないため、脆弱です。また、mysqlライブラリの外で引用してエスケープする必要があります。

関連するSOの質問がありますが、そこにリストされている回答はMySQLDBで機能しないか、SQLインジェクションに対して脆弱です。)




@mluebkeクエリで複数のリストを渡すことについて何か考えはありますか?
Dipen Dedania 2016

回答:


157

list_of_ids直接使用する:

format_strings = ','.join(['%s'] * len(list_of_ids))
cursor.execute("DELETE FROM foo.bar WHERE baz IN (%s)" % format_strings,
                tuple(list_of_ids))

そうすれば、自分自身を引用する必要がなくなり、あらゆる種類のSQLインジェクションを回避できます。

データ(list_of_ids)は(クエリテキストではなく)パラメータとしてmysqlのドライバに直接送信されるため、インジェクションがないことに注意してください。文字列には任意の文字を残すことができ、文字を削除したり引用したりする必要はありません。


2
@heikogerlach:%sを引用していません...最初の行は "%s、%s、%s"の文字列を作成します...同じサイズのlist_of_idsの長さです。
nosklo 2009

ああ、その通りです。もっと見づらくする必要があります。どういうわけか私はそれを混ぜました。しかし、素晴らしい解決策です。

これはsqliteでも機能しますか?原因私はそれを試したところ、構文エラーを指摘しているようです。
Sohaib 2014

sqliteの@Sohaibは置換文字では?ない%sため、最初の行をに変更すると機能しformat_strings = ','.join('?' * len(list_of_ids))ます。
nosklo 2014年

1
あなたのケースで@kdasしたくない% format_strings部分が他の変更するには%s、クエリでのみプレースホルダをIN (%s)プレースホルダ-これを達成するための方法は、すべて倍増することで%交換したいものを除い文字を:query = ("select distinct cln from vcf_commits where branch like %%s and repository like %%s and filename in (%s) and author not like %%s" % format_strings,); cursor.execute(query, (branch, repository) + tuple(fname_list) + (invalid_author,))
nosklo

5

この質問はかなり古いですが、誰かが私が欲しいものを探していた場合に備えて、回答を残したほうがよいと思いました

多くのパラメーターがある場合、または名前付きパラメーターを使用する場合、受け入れられた回答は厄介になります

いくつかの試行の後

ids = [5, 3, ...]  # list of ids
cursor.execute('''
SELECT 
...
WHERE
  id IN %(ids)s
  AND created_at > %(start_dt)s
''', {
  'ids': tuple(ids), 'start_dt': '2019-10-31 00:00:00'
})

でテスト済みpython2.7pymysql==0.7.11


2
これは、python3およびmysql-connector-python8.0.21では機能しません。「PythonタプルをMySQLタイプに変換できません」というエラーが返されます。
rubms

-1

Django 2.0 or 2.1andを使用する場合Python 3.6、これは正しい方法です。

from django.db import connection
RESULT_COLS = ['col1', 'col2', 'col3']
RESULT_COLS_STR = ', '.join(['a.'+'`'+i+'`' for i in RESULT_COLS])
QUERY_INDEX = RESULT_COLS[0]

TABLE_NAME = 'test'
search_value = ['ab', 'cd', 'ef']  # <-- a list
query = (
    f'SELECT DISTINCT {RESULT_COLS_STR} FROM {TABLE_NAME} a '
    f'WHERE a.`{RESULT_COLS[0]}` IN %s '
    f'ORDER BY a.`{RESULT_COLS[0]}`;'
)  # <- 'SELECT DISTINCT a.`col1`, a.`col2`, a.`col3` FROM test a WHERE a.`col1` IN %s ORDER BY a.`col1`;'
with connection.cursor() as cursor:
    cursor.execute(query, params=[search_value])  # params is a list with a list as its element

参照:https//stackoverflow.com/a/23891759/2803344 https://docs.djangoproject.com/en/2.1/topics/db/sql/#passing-parameters-into-raw


-1

この質問はかなり古いですが。それが誰かを助けることができるならば、私は私の解決策を共有しています。

list_to_check = ['A', 'B'] cursor.execute("DELETE FROM foo.bar WHERE baz IN ({})".format(str(list_to_check)[1:-1])

でテスト済み Python=3.6


提供されてlist_to_checkいるものはSQLエスケープされていないため、このソリューションはSQLインジェクション攻撃に対して脆弱であると思われます。これが、値をパラメータとして渡すexecute方が適切な理由です。誰かがこれを使用してシステムを攻撃し、データベースにアクセスする可能性があるため、このソリューションは非常に慎重に使用してください(つまり、入力IDはアプリケーションの外部からパラメーターとして受信されません)。
rubms

-2

リスト内包表記を使用した別の簡単な解決策:

# creating a new list of strings and convert to tuple
sql_list = tuple([ key.encode("UTF-8") for key in list_of_ids ])

# replace "{}" with "('id1','id2',...'idlast')"
cursor.execute("DELETE FROM foo.bar WHERE baz IN {}".format(sql_list))

-4
list_of_ids = [ 1, 2, 3]
query = "select * from table where x in %s" % str(tuple(list_of_ids))
print query

これは、クエリ文字列を完成させるために引数を渡す必要があるメソッドに関心がなく、cursror.execute(query)。だけを呼び出したい場合に、いくつかのユースケースで機能する可能性があります。

別の方法は次のとおりです。

"select * from table where x in (%s)" % ', '.join(str(id) for id in list_of_ids)

-7

非常にシンプル:以下のフォーメーションを使用するだけです

rules_id = ["9"、 "10"]

sql1 = "SELECT * FROMattendance_rules_staff WHERE id in(" + "、" .join(map(str、rules_id))+ ")"

"、" .join(map(str、rules_id))


それはどこでSQL引用を行いますか、そしてこれはバインド変数の代わりにリテラルを使用していませんか?
eckes 2017年

必要はありません、それは単にうまく機能しています。タプル形成は最初の中括弧( "9"、 "10")で文字列として直接変換されるため、テストできます。SQLの形成を調整します。したがって、他のフォーメーションを作成する必要はありません。SQLが隣接しています
Mizanur Ra​​hman

1
rules_idが含まれている場合"); DROP TABLES Bobby --
eckes 2017年

すでに「リストの内

または使用:sql1 = "SELECT * FROM出席_rules_staffWHERE id in(" + "、" .join(map(str、rules_id))+ ")"
Mizanur Ra​​hman 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.