Entity Frameworkで発行するクエリのSQLインジェクション対策

Entity Frameworkで発行するクエリはSQLインジェクション対策はどうするの?

と疑問をお持ちの方向けの記事になります。

Entity Framework はLinqからのクエリや生で直接クエリを発行するなど複数の手段があります。

そこで、安全なクエリ発行方法、そしてSQLインジェクションを受けるクエリ発行方法と
その対策について今回紹介します

それではどうぞ。

クエリはパラメータ化されれば安全

C#でSQLインジェクション対策を行うには一つ、パラメータ化されたクエリになるかどうかです。


パラメータ化された値、上記のクエリでいうと
@name、@age、@studentIdに入る値は意味を持たない文字列として扱われます。

つまり、@name、@age、@studentIdに

DROP文やDELETE文などを入力されても、クエリ上ではただの文字として扱うことができるため、
パラメーター化されたクエリはSQLインジェクションから防御することができます。

Entity Framework で発行されるクエリもこのパラメータ化がされていれば問題ないですよね。

どのような時に、パラメータ化されるのか、されない可能性はないのか確認していきましょう。

Linqだけで作るクエリは安全

Linqで発行するクエリはパラメータ化されます。

select文でどのようにSQLインジェクションを防ぐのか、
とにもかくにもクエリを見てみます。

今回は攻撃用にTable_1を用意しました。

SQLインジェクションが成功すれば、このテーブルは消されます。

それでは、実際にselect文が発行されるC#のコードです。


発行されるWhere句にDROP文を入れます。

そして実際に発行されるクエリはこちら。

Linqで発行されるクエリはパラメータ化されました。

入力したDROP文はパラメータ扱い(@__sqlInjectionString_0=’?’)をされており、
クエリとしてDROP TABLEはでてきません。

つまり、あくまでパラメータとして扱われているので攻撃は失敗です。

モデルを使ったデータ更新も安全

念のためデータ更新についても見てみましょう。


登録するデータに攻撃コードを入れました。

実行結果はこちら。

攻撃コードは@p2にパラメータ化されて、入れられています。

クエリ構文が崩れてエラーになることもなく

攻撃クエリが機能することなく、無事nameカラムに入りました。攻撃は失敗です。

モデルを使ったデータ更新ではパラメータ化されるため、
SQLインジェクション対策が十分されていることがわかります。

今回はinsertだけでの紹介ですが、update,deleteも同様にパラメータ化されます。

生のクエリを使う場合はEntity Frameworkでも注意

生のクエリを発行する場合は、攻撃を受ける可能性があります。

FromSqlメソッドやExecuteSqlRawなどLinqを介さずに直にクエリを発行する場合は注意が必要です。

ですがパラメータ化できれば、Linq同様にSQLインジェクションを防ぐことができます。

FromSqlRaw・ExecuteSqlRawを使う場合は注意が必要

Entity Framework で生のクエリを扱うメソッドはいくつかあるのですけれども、
今回は代表してFromSqlRawメソッドを例に見ていきます。

たとえば、こんなコード


Linqを使わずに、WHERE句に直接攻撃コードをとっています。

発行されるクエリはこちら。

発行されるクエリに、しっかりDROP文がのっかってきます。

残念ながら、Table_1が削除されました。

このように、生のクエリを書く場合はインジェクション攻撃をくらってしまうで注意しましょう。

FromSqlRaw・ExecuteSqlRawを安全に使う方法

ただ誤解してほしくないのは、FromSqlRawメソッド、ExecuteSqlRawメソッドが
危険ではないということです。

当然、SQLインジェクションを受けても大丈夫なように作られています。

今回攻撃コードが機能してしまったのは、FromSqlRawメソッドが悪いわけではなく、
自分でクエリをエスケープもせずに組み立てたのが原因です。

では、攻撃を受けないようにFromSqlメソッドを利用するにはどうすればよいのか?

答えはこうです。


FromSqlRawの第二引数以降で、パラメータ化できるように引き数で変数を受けます。

先ほどWhere句でnameを指定するクエリを文字列連結でつくったのに対して、
パラメータ化された値が入るように、{0}で引き数を受けるれるようにします。

stringのフォーマットメソッドと同様に{0}{1}{2}と、取る引き数に合わせて{数値}を追加できます。
var sample = string.Format(“{0}{1}{2}”, 20, “文字列”, DateTime.Now);

それでは、発行されるクエリを見てみましょう。

Linq同様に、パラメータ化された引き数になり、DROP文が実行されることはありません。

生のクエリを組み立てるのも、SQLインジェクション対策は用意されているので、
しっかりと使っていきたいですね。

まとめ

まとめです。

  • Linqから発行されるクエリはパラメータ化されているので安全
  • 生のクエリもパラメータ化する機能を使って安全に発行できる

もし、生のクエリを使うのが怖いの出れば、Linqで組むか、
パラメータ化が漏れていないことを慎重に確認していく必要があります。

データベースを破壊されないためにも、しっかりとSQLインジェクション対策をしていきたいですね。

では。