はじめに
Djangoでの生のSQL文の正確な書き方の記事がほとんどないので、今回の記事の執筆に至りました。
最初にSQLインジェクションの基本事項を抑え後に、具体的にDjangoのSQLインジェクション対策について見ていきましょう。SQLインジェクションの基本事項は、IPA 安全なアプリケーションの作り方- 1.1 SQLインジェクションを多く参考にさせていただきました。
SQLインジェクションとは?
SQL文の組み立て方法に問題がある場合、攻撃によってデータベースの不正利用を行うこと。
SQLインジェクションの種類
インバウンドSQLインジェクション
webアプリケーションからのレスポンスを収集して脆弱性を分析し、その脆弱性をついたSQL文を実行し、データを盗んだり消去したりすること。さらに以下の二つに分けられる。
- エラーベースSQLインジェクション
攻撃者がデータベースに対してエラーメッセージを生成させるアクションを実行する。 - UNIONインジェクション
複数のSELECTステートメントの結果を一つの結果に結合し、HTTPレスポンスの一部に結果が含まれて返ってくる。
ブラインドSQLインジェクション
攻撃者がデータをwebサーバーに送信し、webサーバーのレスポンスと動作を観察・分析することによって、攻撃者がデータベースの管理情報を盗むことができる。
発生しうる脅威
IPA 安全なアプリケーションの作り方- 1.1 SQLインジェクションで以下のように説明されています。
- データベースに蓄積された非公開情報の閲覧
- データベースに蓄積された情報の改ざん、消去
- 認証回避による不正ログイン
- ストアドプロシージャ等を利用したOSコマンドの実行
一般的な対策
- SQL文の組み立ては全てプレースホルダーで実装する。
文字列連結に対して機械的な処理でSQL文が組み立てられるので、SQLインジェクションを解消できる。プレースホルダーに実際の値を割り当てることをバインドと呼び、データベースエンジンで割り当てる静的プレースホルダーと、アプリケーション側で割り当てる動的プレースホルダーがある。より安全なのは前者。 - SQL文の組み立てを文字列連結によって行う場合は、エスケープ処理等を行いSQL文のリテラルを正しく構成する。
- webアプリケーションに渡されるパラメータにSQL文を直接指定しない。
次にDjangoについて具体的に見ていきましょう。
Djangoで既に行われているSQLインジェクションへの対策
ORMによって対策されている。ORMとは、Object-relational mapper
の略。これは、オブジェクト志向言語を用いることで、プログラム内のシステム間でデータの非互換なやり取りを行う技法。つまり、オブジェクトを操作することでデータの管理を行うことを可能にした。これを行うことで、クエリのパラメータ化が行われ、それをデータベースドライバーによってエスケープするため、SQLインジェクションを防御できている。
生のSQL文を書く時の注意点
Djangoで既に対策されているとはいえ、複雑なクエリを叩きたい時やデータがモデルに対応していない時など、生のSQL文を書きたい時がある。その時は、次のような二つの記法のうちどちらかを用いる必要がある。
- executeを用いた際の対処法
context = super().get_context_data(**kwargs)
con = sqlite3.connect("db.sqlite3")
cur = con.cursor()
sql_input = self.request.GET.get("sql", None)
# プレースホルダーを設ける
sql = "SELECT * FROM books_Book WHERE id = %s"
# 値の入れ方に注意
cur.execute(sql % (sql_input))
context["data"] = cur.fetchone()
con.close()
return context
- Raw()を用いた際の対処法
context = super().get_context_data(**kwargs)
sql_input = self.request.GET.get("sql", None)
# プレースホルダーを設けて値の代入も行う
item = Item.objects.raw("SELECT * FROM items_Item WHERE id=%s", str(sql_input))
context["data"] = item[0].overview
return context
最後に
SQLインジェクションは非常に危険性の高い攻撃ですが、Djangoは基本的にORMによって対策できているようなので、Djangoでコードを書くときはあまり意識する必要はないでしょう。ただ生のSQL文を書く時は、上記の書き方を参考にしていただきたいです。
また初めてのqiitaへの投稿なので、至らない点もあると思いますので、その場合は是非コメントなどをお寄せください。
参考資料
IPA 安全なアプリケーションの作り方- 1.1 SQLインジェクション
油断できない SQL インジェクション。その種類と Web アプリにおける対策
DjangoのSQLインジェクション対策
Djangoの公式のSQL解説