主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

Python: GQLインジェクションはできるか。できんかった。

                
tags: python
 Webサイトなどをつくるとき、すくなくとも2つチェックしておかねばならないセキュリティ事項がある。クロスサイトスクリプティングとSQLインジェクションだ。今回はpythonでGoogleAppEngineでWebサイトを作成するとき、データベースとして使われる『データストア』に対してSQLインジェクションのようなことを仕掛けることができるのかを考えてみる。ちなみにデータストアに対してクエリを送る言語は、『GQL』という名前だ。つまり今回やろうとするのは『GQLインジェクション』。参考は徳丸本と呼ばれる『安全なWebアプリケーションの作り方』。おもにPHPアプリケーションでの実行例が載っており、これがPython+GAE環境では実行できるかということを検証していく。

0. execを使わない
 まずこれは基本中の基本。先に結果から言えば、GQLインジェクションはできなかったし、そういったセキュリティとして安全なものを作るためのGoogleの工夫をいくらか目の当たりにした。URLのクエリから受け取った文字列をexecに渡すなんてことをしたら、任意のコードを実行できることに他ならない。そうすると、Googleの工夫は無駄に帰す。データストアからの情報の盗み出し、改ざんが可能になる。
 


1. エラーメッセージを経由して情報を得る
http://sample.jp/hoge.php?author=Shakerspeare

PHPで動かしているあるサーバに対して、クライアントに期待する模範的なリクエストは上記。下記のURLでリクエストを送ると、エラーメッセージとともにパスワードが表示され得る。
http://sample.jp/hoge.php?author='+and+cast((select+id||':||'pwd+from+users+offset+0+limit+1)+as+integer)>1--

まず、GoogleAppEngineでWebアプリをデプロイするときは、デバッグモードをオフにしておく。エラーメッセージがクライアントに送られるようにしない。
app = webapp2.WSGIApplication([('/prepare', Prepare),
('/test1', Test1),
],debug=False)

あとはexec関数を使っていなければ、クエリにあるようなスクリプトもただの奇怪な文字列でしかない。これをクエリにかけたところで、通常はなにも返ってこないだろう。



2. 認証回避
クライアントからIDとパスワードを受け取って、データベースにクエリを発行してIDとパスワードが一致するものを取ってくるというのがある。このときデータベースへのクエリを以下のようにしていたとする。
SELECT * FROM user WHERE id='$id' AND pwd='$pwd'
もし$pwdに『' OR 'A'='A』という文字列が入っていたらクエリは以下のようになってしまう。
SELECT * FROM user WHERE id='ore' AND pwd='' OR 'a'='a'
idは『ore』でなく、任意なものにできる。そうするとクエリ末尾のOR以降のステートメントが常に真であるから、パスワードが正しくなくてもログインできることになってしまう……、というのが徳丸本でのPHPの例。
GQLでは? ORがないのでこんなことはできない。



3. そもそも想定外の挙動をしないデータベースクエリを発行しよう
文字列連結を使ってクエリを作るのはあまりよろしくない。末尾に意図しない条件を加えて行けるからだ。
GqlQuery("SELECT * FROM author WHERE name = " + "'Herman Hesse'")
GQLにはプレースメントが用意されているので、そっちをつかっていくのが望ましい。
GqlQuery("SELECT * FROM author WHERE name = :1", "Herman Hesse")
GqlQuery("SELECT * FROM author WHERE name = :name1", name1="Herman Hesse")
また、Queryというクラスを使うのもいい。安全でわかりやすい記述でデータベースから値を引っ張ってこられる。
class author(db.Model):
title = db.StringProperty()

query = db.Query(author).filter("name =", "Herman Hesse")




まとめ
徳丸本からSQLインジェクションの例を引っ張ってきて、GQLインジェクションを試みたが、インジェクションはできなかった。ググってみても、具体的にインジェクションに成功したというものは出て来ず、インジェクションを起こされないクエリを発行する方法が載っている程度だった。というわけで、
・そもそもPythonスクリプトにexec()を使わない
・デバッグモードを切る
・クエリは発行にはプレースメントを使うか、Queryクラスを使う
ということを守っていれば、インジェクションはできなさそうである。
スポンサーサイト



プロフィール

h

Author:h

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon