Python의 SQL 문에서 변수를 사용하는 방법은 무엇입니까?


91

좋아, 나는 파이썬에 익숙하지 않다.

다음 Python 코드가 있습니다.

cursor.execute("INSERT INTO table VALUES var1, var2, var3,")

여기서는 var1정수이고 var2& var3는 문자열입니다.

쿼리 텍스트의 일부로 포함하는 파이썬없이 변수 이름을 어떻게 쓸 수 있습니까?

답변:


103
cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3))

매개 변수는 튜플로 전달됩니다.

데이터베이스 API는 변수의 적절한 이스케이프 및 인용을 수행합니다. 문자열 형식화 연산자 ( %) 를 사용하지 않도록주의하십시오.

  1. 이스케이프 또는 인용을 수행하지 않습니다.
  2. 제어되지 않는 문자열 형식 공격 (예 : SQL 주입 )에 취약합니다 .

흥미롭게도 배열 (var1, var2, var3) 대신 vars와 별도로 작동하는 이유는 무엇입니까?
Andomar

DB API 사양에 따르면 python.org/dev/peps/pep-0249
Ayman Hourieh

9
@thekashyap주의 깊게 다시 읽으십시오. 안전하지 않은 것은 문자열 형식화 연산자를 사용하는 것 %입니다. 사실 저는 대답에서 그렇게 말합니다.
Ayman Hourieh

내 잘못이야 .. 문자열과 변수 사이에 있는 % 대신에 ,.. 여러 가지 이유로 내 투표를 취소 할 수 없다고 생각했습니다. 't 사용 %..
쉬얍

1
@eric 대답은 % 연산자 를 사용하여 문자열을 형식화 하지 마십시오 . 이러한 %문자열은 사용중인 cursor.execute직접, 그리고 그것의 생성 SQL을 알고 있기 때문에 당신을 보호하기 위해 더 많은 일을 할 수 있습니다.
Mark Ransom

66

Python DB-API의 다양한 구현은 다른 자리 표시자를 사용할 수 있으므로 사용중인 자리 표시자를 찾아야합니다 (예 : MySQLdb 사용).

cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3))

또는 (예 : Python 표준 라이브러리의 sqlite3 사용) :

cursor.execute("INSERT INTO table VALUES (?, ?, ?)", (var1, var2, var3))

또는 아직 다른 것 ( 또는 "이름이 지정된 스타일"을 VALUES가질 수 있거나 에 대한 두 번째 인수로지도 대신 dict를 전달하는 위치 ). 사용중인 DB API 모듈에서 문자열 상수를 확인하고 http://www.python.org/dev/peps/pep-0249/ 에서 paramstyle을 찾아 모든 매개 변수 전달 스타일이 무엇인지 확인하십시오!(:1, :2, :3)(:fee, :fie, :fo)(%(fee)s, %(fie)s, %(fo)s)executeparamstyle


동일한 작업을 수행 할 수 있지만 외부 SQL 스크립트를 사용할 수 있습니까?
Novitoll

46

여러 가지 방법이 있습니다. NOT DO (가장 눈에 띄는 하나를 사용 %s%실제 코드를), 그것은 개방의 공격 .

여기 sqlite3의 pydoc에서 복사하여 붙여 넣습니다 .

# 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()

# Larger example that inserts many records at a time
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
             ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
             ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
            ]
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)

필요한 경우 더 많은 예 :

# Multiple values single statement/execution
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', ('RHAT', 'MSO'))
print c.fetchall()
c.execute('SELECT * FROM stocks WHERE symbol IN (?, ?)', ('RHAT', 'MSO'))
print c.fetchall()
# This also works, though ones above are better as a habit as it's inline with syntax of executemany().. but your choice.
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', 'RHAT', 'MSO')
print c.fetchall()
# Insert a single item
c.execute('INSERT INTO stocks VALUES (?,?,?,?,?)', ('2006-03-28', 'BUY', 'IBM', 1000, 45.00))

4
일부 DB-API 구현은 실제로 변수에 % s를 사용합니다. 특히 PostgreSQL의 경우 psycopg2를 사용합니다. 문자열 대체를 위해 % s를 % 연산자와 함께 사용하는 것과 혼동해서는 안됩니다 (쉽기는하지만). 이식성을 위해 DB-API에 대한 SQL 매개 변수를 지정하는 정의 된 표준 방법을 가질 수 있다면 정말 좋을 것입니다.
ThatAintWorking 2014

24

http://www.amk.ca/python/writing/DB-API.html

단순히 변수 값을 문장에 추가 할 때주의하십시오. 사용자가 자신의 이름을 지정한다고 상상해보십시오. ';DROP TABLE Users;'그렇기 때문에 적절한 방식으로 cursor.execute를 사용할 때 Python이 제공하는 SQL 이스케이프를 사용해야합니다. URL의 예는 다음과 같습니다.

cursor.execute("insert into Attendees values (?, ?, ?)", (name,
seminar, paid) )

13
실제로 SQL 이스케이프가 아닙니다. 훨씬 더 간단하고 직접적인 변수 바인딩입니다. 값은 구문 분석 후 SQL 문에 바인딩되므로 주입 공격에 영향을받지 않습니다.
S.Lott

글쎄, SQL 이스케이프인지 변수 바인딩인지는 데이터베이스 서버 / DB-API 드라이버가 얼마나 좋은지에 달려 있습니다. DB-API 드라이버가있는 실제 널리 배포 된 프로덕션 데이터베이스 중 일부는 유선에서 데이터와 코드를 대역 외로 유지하는 대신 이스케이프 만 수행하는 것을 보았습니다. 말할 필요도없이, 소위 "데이터베이스"에 대한 존경심이별로 없습니다.
Charles Duffy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.