2017-06-15 6 views
0

私は、CSV形式のSQLiteテーブルからデータを返す小さなPython/Flask Webアプリケーションを持っています。 sqlite3コマンドラインプログラムを使用してクエリ結果を直接CSVファイルにエクスポートし、クエリ結果をPythonに読み込んでメモリ内のファイルに書き込んでから、CSVファイルを返す方が速いことがわかったメモリ内ファイル。しかし、sqlite3プログラムを使用すると、私は自分のアプリケーションをSQLインジェクション攻撃にさらしてクエリを構築する必要があります。PythonでSQLiteクエリを作成しますが、sqlite3コマンドラインプログラムを使用してSQLiteクエリを実行しますか?

より速く、しかし

queries = """ 
.mode csv 
.headers on 
.output /tmp/results.csv 
SELECT * FROM mytable WHERE foo = '{0}'; 
""".format(user_input) 

subprocess.check_output(
    ["sqlite3", "/path/to/mydb.sqlite"], input=bytes(queries.encode("utf-8"))) 

return send_file("/tmp/results.csv", mimetype="text/csv") 

SQLインジェクションから安全な、しかし遅く

conn = sqlalchemy.create_engine("sqlite:////path/to/mydb.sqlite") 
result = conn.execute("SELECT * FROM mytable WHERE foo = ?", (user_input,)) 

csvfile = io.StringIO() 
csvwriter = csv.writer(csvfile) 
csvwriter.writerow(result.keys()) 

for row in result.fetchall(): 
    csvwriter.writerow(row) 

return Response(csvfile.getvalue(), mimetype="text/csv") 

SQLインジェクション攻撃に対して脆弱私はPythonライブラリ(sqlalchemyのを、使用することができる方法はありますSQLインジェクションから安全ですが、実際にはクエリを実行しないクエリを作成するために、代わりに0を使用してサブプロセスを介してクエリを実行することができますコマンドラインプログラム?

答えて

0

直接SQLiteのツーCSVエクスポートパス(sqlite3プログラムの.mode csvを使用)は、主に大量のデータを選択する場合には、より巡回的なSQLiteからPythonへのCSVエクスポートパスよりも速度上の利点があります。より少ないデータ量を選択する場合、速度はあまり変わらない。

スキーマによっては、Pythonを使用してデータベースにIDセットを照会し、sqlite3を使用してIDを使用して残りのデータを選択することもできます。こうすることで、Pythonライブラリはユーザの入力を害する(SQLインジェクションなどを防ぐ)ことができ、sqlite3プログラムに渡すものはユーザ入力ではなく、あなた自身が照会するIDになります。

conn = sqlalchemy.create_engine("sqlite:////path/to/mydb.sqlite") 
result = conn.execute("SELECT ID FROM mytable WHERE foo = ?", (user_input,)) 
ids = [row[0] for row in result.fetchall()] 

queries = """ 
.mode csv 
.headers on 
.output /tmp/results.csv 
SELECT * FROM mytable WHERE ID IN ({0}); 
""".format(",".join([str(id) for id in ids])) 

subprocess.check_output(
    ["sqlite3", "/path/to/mydb.sqlite"], input=bytes(queries.encode("utf-8"))) 

return send_file("/tmp/results.csv", mimetype="text/csv") 

このアプローチでは、1ではなく2つのクエリが含まれますが、ボトルネックがすべてのデータを選択している場合は、その差はわずかです。あなたのアプリをプロファイルして確かめてください。

0

SQL文字列の中で、唯一の特殊文字は、引用符'です。 (クエリ全体を終了し、構文エラーになり、コード0、との文字。)

単一引用符をエスケープするためには、それらを倍増:

user_input.replace("'", "''") 
関連する問題