SQLインジェクションは本当に避けられないのか

ドクジリアン柔術少女 すから☆ぱいそん

ありもしない完全な代替品を求めるよりも、より現実的な選択肢を改善することについて。

というツイートをしたところ、

  • 何をいうか。必ずORMを使うべきだ
  • SQLは根本的にSQLインジェクションを回避できない問題がある

みたいな趣旨の反応があったのだけれど、前者についてはWikipediaのここ を一読いただくとして、後者についてはプログラミング言語のほうが発達してて状況が違ってきてるよという話をしたい。

誤解しないでいただきたいのは、別にSQLが良いものであるとは言ってないことだ。良くないものであっても現実的な話としてそれしか選択肢がないのであればそれと向き合うための工夫が必要なのであって、それに真面目に取り組むことは素晴らしいのだということである。

ScalikeJDBCのSQL型

ScalikeJDBCを使う場合において、SQLはそれがソースに記述された時点で文字列ではなく SQL型のオブジェクトとして扱われる。

sql"select * from emp where name='scott'"

上記の記述はいっけん文字列に見えるが、先頭に付いているsql がこれを文字列と異なる SQL型のオブジェクトであると示している。型が違うので文字列とは連結できないし、文字列との相互変換もできない。例えば下記の記述はコンパイル時点でエラーになる。

val name = "scott"
sql"select * from emp where name='" + name + "'"

大事なことなのでもう一度。上記のコードは コンパイル時点でエラーになる。正しくは

val name = "scott"
sql"select * from emp where name=${name}"

のようにSQL型のオブジェクトに所定の書式で直接パラメータを埋め込む。SQL型のオブジェクトに埋め込まれたパラメータはScalikeJDBC内部で実行時にエスケープされるため、そこにどんなアブナイ入力値が潜んでいようともSQLインジェクションは起こらない。逆に言えば、SQLインジェクションが起こるのはアブナイ入力値を文字列連結でSQLに埋め込むからだ(そしてHQLやJPQLのようなORMの独自クエリ言語だって同じ問題を抱えている)。ならSQLと文字列の連結をそもそも不可能にしてしまえばいいというわけである。

(SQL文字列にプレースホルダを埋め込む典型的な PreparedStatement方式とどう違うのかと思われる方は、「コンパイルの時点で」間違いを検出出来るかどうかの違いについて考えてみてほしい)

SQLインジェクションは必ずしも不可避ではない

原因がミスにせよ知識不足にせよSQLインジェクションが起こる可能性のあるコードがコンパイラに弾かれさえすれば、それがサービスインして問題を起こすに至ることも当然ありえないことになる。旧来のプログラミング言語ではSQLを"文字列"として処理するしか方法がなかったため SQLインジェクションを起こしうる操作を禁止することは確かにできなかったが、言語が進化し物事に"文字列"やら"数値"やらといったプリミティブよりも複雑な意味をより静的に与えられるようになった今では、「根本的にSQLインジェクションは不可避である」とは言えないことになる。

(もっとも、常に最新のプログラミング言語を採用してモノを作れるわけではないという問題は別にある)

同じカテゴリの記事

カテゴリ ドクジリアン柔術少女 すから☆ぱいそん の記事一覧
企業向けニッチ製品にフリーミアムは通用するのか 2015年1月9日
【宣伝】ドンキに行ったら外国人がすごかった(メディアファクトリー社刊) 2014年12月18日
オタクと常識人 2014年12月5日
テキトーな人達と、不必要に細かい人達 2014年11月30日
SPAとログイン認証 2014年11月27日

お勧めカテゴリ

英語でアニメ観ようず
なじみ深い日本製アニメの英語版DVDで、字幕と音声から英語を学びましょうという趣旨のシリーズ記事です。
ScalaのようでJavaだけど少しScalaなJSON API
Scalaと Spring Frameworkを使って REST的なJSON APIを実装してみましょう。
ドクジリアン柔術少女 すから☆ぱいそん
代表 嶋田大貴のブログです。写真は神仏に見せ金をはたらく罰当たりの図