ここまでをまとめてみると、LINQ to SQLでインジェクションが排除されるのは、ユーザーが動的クエリではなくコンパイル済みのコードを使用するためです。LINQクエリが実行するのは読み取りだけなので、Selectは可能ですが、Delete、UpdateまたはInsertは不可能です。バックエンドにあるデータの変更は、クエリではなくメソッド呼び出しを経由して行われます。リスト3では、リスト2のコード(コンソールアプリケーション)を改造して、LINQ to SQLで同じタスクを実行する方法を解説します。
Imports System.Linq Imports System.Data.Linq Imports System.Data.Linq.Mapping Module Module1 Sub Main() CorrectedVersionWithLINQToSQL() End Sub Sub CorrectedVersionWithLINQToSQL() Dim northwind As Northwind = New Northwind Dim customers As Table(Of Customer) = _ northwind.GetTable(Of Customer)() Dim param As String = "ALFKI" Dim results = From cust In customers _ Where cust.CustomerID = param _ Select cust For Each c In results Console.WriteLine(c.CustomerID) Console.WriteLine(c.CompanyName) Next Console.ReadLine() End Sub End Module Public Class Northwind Inherits DataContext Public Shared ReadOnly connectionString AsString = _ "Data Source=.\SQLExpress;Initial _ Catalog=northwind;Integrated Security=True" Public Sub New() MyBase.New(connectionString) End Sub End Class <Table(Name:="Customers")> _ Public Class Customer Private FCustomerID As String <Column()> _ Public Property CustomerID() As String Get Return FCustomerID End Get Set(ByVal Value As String) FCustomerID = Value End Set End Property Private FCompanyName As String <Column()> _ Public Property CompanyName() As String Get Return FCompanyName End Get Set(ByVal Value As String) FCompanyName = Value End Set End Property End Class
Northwind
クラスには、バックエンドのSQLデータベースへの接続に必要なものすべてが揃っています。ADO.NETを直接使用することはありません。Northwind
クラスはDataContext
クラスを継承しており、接続文字列を指定してベースのコンストラクタを呼び出します。Customer
クラスはエンティティクラスと呼ばれるクラスです。このクラスは、TableAttribute
属性でCustomersテーブルにマッピングされ、設計したとおりにCustomersテーブルからCustomerIDとCompanyNameのみを返します。DataContext
クラスとTable
クラスが他の場所からこれ以外のデータを返すことはできません。
LINQ to SQLクエリは、Moduleに記述されています。Northwind
クラスのインスタンスを生成してTable(Of Customers)
にリクエストを送信し、LINQクエリで目的のデータを選択する単純なものです。このサンプルを見れば分かるように、LINQはコンテキストを設定するFrom句で始まり、Select句で終わります。Intellisense(インテリセンス)による補助もあります(初めは少し戸惑いますが、すぐに慣れるでしょう)。
混乱を引き起こそうと画策する悪知恵の働く者が大勢いるようなので、たった1つの方法であらゆる攻撃を阻止できる保証はありません。攻撃を受けて損害を被る可能性があるときは、情報の保護に必要な時間、労力およびコストと比較して検討する必要があります。また、セキュリティというのは全体論的な問題であり、企業内外の人々とその行動をひっくるめて考える必要があります。
読者の皆さんは非常に優秀な方ばかりだと思うので、興味があれば、悪意のある値をパラメータに挿入して有用な情報を入手する方法を考えてみてください。条件として、変更できるのはパラメータの値のみとします。成功した場合には、ぜひその成果を発表してください。
まとめ
LINQ to SQLでは、ユーザーに動的SQLではなくコンパイル済みのコードを使用させることで、SQLインジェクションを回避します。これはつまり、エンドユーザーは本来の意図とは異なるクエリをパラメータとして渡すことができないということです。このクエリ言語はSelect構文のみをサポートし、Update、DeleteまたはInsertはサポートしていないため、LINQ to SQLでは有害なSQLインジェクションが阻止されます。更新処理はすべてメソッド呼び出しを経由して行われるため、当然ながらインジェクションは不可能です(インジェクションが機能しうる唯一の方法は、CodeDOMを使用して、ユーザーの入力した文字列を動的にコンパイルするコードを書く場合です)。
最後になりますが、LINQ to SQLで私が最も気にいっているのは、ADO.NETで周辺処理をすべて記述することに比べて、LINQ to SQLの方が書きやすく使いやすい点です。LINQを本気でマスターしたいときは、Amazon.co.jpやどこか良い書店で拙著『LINQ Unleashed for C#』をお買い求めください。VBしかわからないという方でも、解説は普通の文章(英語)で書かれていますし、コードはダウンロード可能なので、ぜひお試しください。VBとC#は二卵性の双子のようなものなので、VBが分かればC#も読むことができます。