2017-01-25 9 views
2

사용자가 결과가 표시되는 순서를 선택할 수 있기를 바랍니다. 나이별로), 데이터베이스에서 가져온 후에 정렬하고 싶지 않습니다.SQL 삽입을 피하기 위해 pysqlite의 열 이름을 어떻게 매개 변수화해야합니까?

분명히 사용자가 SQL 명령에 영향을주는 입력을 지정할 수 있다면 위생 처리가 필요하며 일반적으로 parameterisation을 사용하지만 pysqlite는 값을 제외한 매개 변수를 무시하는 것 같습니다.

예제 코드는 ORDER BY에 대해 작동하지 않는 매개 변수화를 보여 주며 문자열 형식을 사용하는 해결 방법이지만 SQL 주입에 취약합니다.

SQLi 취약점을 노출하지 않고 사용자 입력이 정렬 순서에 영향을 줄 수있는 권장 솔루션은 무엇입니까? 문자열 형식을 사용하고 모든 사용자 입력을 수동으로 확인해야합니까?

#!/user/bin/env python3 

import sqlite3 

con = sqlite3.connect(':memory:') 
cur = con.cursor() 
cur.execute('CREATE TABLE test (name, age)') 
cur.execute('INSERT INTO test VALUES (:name, :age)', {'name': 'Aaron', 'age': 75}) 
cur.execute('INSERT INTO test VALUES (:name, :age)', {'name': 'Zebedee', 'age': 5}) 

cur.execute('SELECT * FROM test ORDER BY age ASC') 
results = cur.fetchall() 
print('\nGood, but hard coded:\n', results) 
# Good, but hard coded: 
# [('Zebedee', 5), ('Aaron', 75)] 

cur.execute('SELECT * FROM test ORDER BY :order_by ASC', {'order_by': 'age'}) 
results = cur.fetchall() 
print('\norder_by parameter ignored:\n', results) 
# order_by parameter ignored: 
# [('Aaron', 75), ('Zebedee', 5)] 

cur.execute('SELECT * FROM test ORDER BY {order_by} ASC'.format(order_by='age')) 
results = cur.fetchall() 
print('\nRight order, but vulnerable to SQL injection:\n', results) 
# Right order, but vulnerable to SQL injection: 
# [('Zebedee', 5), ('Aaron', 75)] 

con.close() 
+0

나는이 입력으로 SQLi를 사용하여 방금 시도했다. ''나이; DROP TABLE 테스트 - 세 번째 SQL 명령에 '' '를 쓰고 pysqlite가'sqlite3.Warning : 한 번에 하나의 명령문 만 실행할 수 있습니다.'라는 예외를 발생 시켰으므로 걱정하지 않아도 될까요? 그래도 여전히 문자열 서식을 사용하는 것이 위험한 것 같습니다 ... – Grezzo

+0

사용자가 문자열의 실제 내용에 어떤 방식 으로든 영향을 미칠 수 있습니까? (질문에서, 당신은 일정하지 않은''age ''라는 상수 문자열을 사용하고 있습니다.) –

+0

이것은 HTTP 요청에서 나옵니다. 적절한 클라이언트 (웹 페이지)를 사용하는 경우 6 개의 열 이름 중 1 개가되어야하지만, 누군가가 악의적 인 것으로 결정하면 선택하는 것이 될 수 있습니다. – Grezzo

답변

3

SQL 매개 변수는 값에만 사용됩니다. 다른 것이 쿼리의 의미를 바꿀 수 있습니다. 당신이 허용 된 사이트 목록 사용할 수,

클라이언트에서 열 이름이 유효한지 확인하기 위해 (. 예를 들어, ORDER BY (SELECT ... FROM OtherTable ...)을 할 수로 ORDER BY password는 힌트를 떠날 수) :

if order_by not in ['name', 'age']: 
    raise ... 
execute('... ORDER BY {}'.format(order_by)) 

을하지만 여전히 나쁜 생각 유효성 검사와 실제 테이블이 동기화되지 않거나 검사를 잊어 버릴 수 있기 때문에 해당 문자열을 쿼리에 통합 할 수 있습니다.

order_by = ['name', 'age'][order_index] 
execute('... ORDER BY {}'.format(order_by)) 
+0

상수를 사용하여'order_index' 이름의 값을 지정합니다 (예 :'NAME_COLUMN = 0'). 이렇게하면 쉽게 열을 더 추가하거나 주위로 이동시킬 수 있으며 원하는 정렬 순서를 볼 수 있습니다. –

+0

또한 'name ASC, age DESC'와 같이 더 복잡한 순서를 쉽게 만들 수 있습니다. –

+0

좋은 대답, 특히 열을 기준으로하는 주문은 암호 힌트를 줄 수 있습니다. 감사. 허용 목록은 그 때이다. – Grezzo