web-dev-qa-db-ja.com

SQLAlchemy + SQLインジェクション

SQLAlchemyを使用するときにSQLインジェクション攻撃を軽減するためのベストプラクティスは何ですか?

50
Mike

データに「特殊」文字(セミコロンやアポストロフィなど)が含まれている場合は、SQLEngineオブジェクトによって自動的に引用されるため、引用を気にする必要はありません。これは、SQLAlchemyの引用メカニズムを意図的にバイパスしない限り、SQLインジェクション攻撃は基本的に不可能であることも意味します。

[ http://www.rmunn.com/sqlalchemy-tutorial/tutorial.html あたり]

45
Andreas Jung

tldr:生のSQLをできるだけ避けます。

受け入れられた答えは怠惰で正しくありません。 filterメソッドは生のSQLを受け入れ、そのように使用された場合、SQLインジェクション攻撃の影響を完全に受けます。たとえば、URLから値を受け入れ、それをフィルターで生のSQLと組み合わせる場合、攻撃の可能性があります。

session.query(MyClass).filter("foo={}".format(getArgs['val']))

上記のコードと以下のURLを使用して、SQLをフィルターステートメントに挿入します。上記のコードは、データベース内のすべての行を返します。

http://domain.com/?val=2%20or%201%20=%201

63
Tendrid

@ Tendrid answer に追加します。私は静かな素朴なアプローチを使用して少し調査をしました。 filterメソッドの引数は*criterionですが、他のいくつかのORMクエリメソッドにも同様の引数があります。

filterメソッドの場合*criterion引数は最終的に _ literal_as_text に渡されます。これは文字列の場合-安全なSQLとしてマークします(間違っている場合は修正してください) 。したがって、安全ではありません。

ORM Query class*criterion引数を使用したメソッド調査の結果は次のとおりです。

filter   - uses _literal_as_text (NOT SAFE)
having   - uses _literal_as_text (NOT SAFE)

distinct - uses _literal_as_label_reference (NOT SAFE)
group_by - uses _literal_as_label_reference (NOT SAFE)
order_by - uses _literal_as_label_reference (NOT SAFE)

join     - uses model attributes to resolve relation (SAFE)

可能性のあるメソッドの誤用の例(簡単にするために、文字列のフォーマットはスキップされます):

db.session.query(User.login).group_by('login').having('count(id) > 4; select name from roles').all()
db.session.query(User.login).distinct('name) name from roles /*').order_by('*/').all()
db.session.query(User.login).order_by('users_login; select name from roles').all()
db.session.query(User.login).group_by('login union select name from roles').all()

これらのメソッドは、文字列リテラルが渡された場合にのみ安全でないことに注意してください。

5
aisbaa