SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

LINQ to SQLが通常のSQLより優れた選択肢である理由

LINQ to SQLを使ってSQLインジェクションを防止する

  • X ポスト
  • このエントリーをはてなブックマークに追加

 本稿では、LINQ to SQLを使って空のクエリに値を設定することでSQLインジェクションを防止する方法について解説します。つまり、LINQはデータベースにSQLを渡す ための優れた代替手段です。LINQ to SQLは通常のADO.NETやSQLと比べて簡単なばかりでなく、SQLインジェクションの防止という設計上の副次効果が期待できます。

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめに

 私は悪意のあるプログラムの作り方を知っています。随分昔になりますが、古いcommand.comにMichelangeloウイルスを埋め込む方法を見つけたときには、command.comでスピーカーのポートを開いたり、ビープ音が鳴り続けるようにしたことがあります。BIOS割り込みでキーボードの入力を監視するプログラムを書いたこともあります。これは20年ほど前の話で、それ以降、その好奇心を育てることはありませんでした。ですから、時々友人がボットやワーム、ポップアップ広告などを駆除するのを手伝ったりしていることを除けば、決して悪意あるコードのエキスパートなどではありません。むしろ、その手のコードを作成する輩にはうんざりしています。

 そうは言っても、悪意のあるコードを書く人々はやはり存在します。おそらく彼らの行動の裏には、好奇心が強いとか、雇い主やだれかから何かをくすねようとしているなどの理由があるのでしょう。このような悪意の現れの1つに、SQLインジェクション攻撃があります。

 SQLインジェクションの流れはこうです。何らかのユーザー入力から値を受け取るSQLがあり、そのSQLがデータベースに渡されるとします。悪意あるユーザーはこのSQLに、所定のパラメータの代わりに、自分で書いたSQLを最後に付け加えたパラメータを渡して、不正な処理を実行させようとします。

 本稿では、LINQ to SQLを使って空のクエリに値を設定することでSQLインジェクションを防止する方法について解説します。つまり、LINQはデータベースにSQLを渡すための優れた代替手段です。LINQ to SQLは通常のADO.NETやSQLと比べて簡単なばかりでなく、SQLインジェクションの防止という設計上の副次効果が期待できます。

悪意あるSQLインジェクションとはどういうものか

 Webサイトの設計によっては、SQLコマンドの組み立てにユーザー入力データを用いているかどうかを、ごく簡単に見分けることができます。ブラウザでWebサイトを開き、SQLの未終了文字列のエラーを発生させるようなデータ(一重引用符など)を入力し、そのWebサイトが暴走するかどうかを確認するのです。Webサイトが暴走したとき、そのサイトが運よくデバッグモードで配置されていれば、おそらくADO.NETのコードが実際に表示されます。

 図1は、顧客IDを入力すると対応する会社名が表示される簡単なWebサイトです(ほとんどの読者がアクセスできるように、Northwindデータベースを使用)。ただし、悪意あるユーザーが一重引用符を入力すると、このサイトはクラッシュします。デバッグモードの場合、入力したコードをSQL Serverに送っているという情報が、悪意あるユーザーに知られてしまいます。

図1 正しい顧客IDを入力すると会社名が表示される
図1 正しい顧客IDを入力すると会社名が表示される
図2 閉じていない引用符のエラーが発生してソース行が表示される。それほどエラーチェックをしないでユーザー入力をSQL Serverに渡していることが分かる
図2 閉じていない引用符のエラーが発生してソース行が表示される。それほどエラーチェックをしないでユーザー入力をSQL Serverに渡していることが分かる

 こうなると、悪意あるユーザーは顧客IDの代わりに巧妙なSQLを組み立てて、フィッシングに取りかかります。最も狙われやすい場所が、マスタテーブルです。まずリスト1で、このサンプルWebサイトのコードを見てください。

リスト1 SQLインジェクション攻撃を受けやすいコード。ユーザー入力がそのままSQL Serverに送信されている
Imports System.Data.SqlClient

Partial Public Class _Default
   Inherits System.Web.UI.Page

   Protected Sub Page_Load(ByVal sender As Object, _
      ByVal e As System.EventArgs) Handles Me.Load

   End Sub

   Protected Sub Button1_Click(ByVal sender As Object, _
      ByVal e As EventArgs) Handles Button1.Click

      Dim connectionString As String = _
         "Data Source=.\SQLExpress;Initial>span _
            Catalog=northwind;Integrated Security=True"

      Dim sql As String = _
         "SELECT CustomerID, CompanyName FROM Customers _
            WHERE CustomerID = '{0}'"

      Using connection As SqlConnection = _
         New SqlConnection(connectionString)
         connection.Open()
         Dim command As SqlCommand = _
            New SqlCommand(String.Format(sql, _
               TextBox1.Text), connection)

      Dim table As DataTable = New DataTable
      Dim adapter As SqlDataAdapter = New SqlDataAdapter(command)
      adapter.Fill(table)

      GridView1.DataSource = table
      GridView1.DataBind()

      End Using
   End Sub
End Class

 このサンプルでは、コードのとおりに「TextBox.Text」から値を読み込み、エラーチェックをしないでその値をSQLに埋め込みます(このようなコーディングはお勧めしません。こうしたコードが本番環境で使われている場合もありますが、上記はインジェクションの仕組みを示すごく典型的な例です)。

 次に、悪意あるユーザーが、顧客IDを入力せずに次のようなテキストを入力したとします。

"ALFKI' UNION SELECT 'database name' as dummy, name _
FROM master.sys.databases --"

 上記のテキストによって、一見すると何の変哲もないリスト1のSQLから、次のSQLができあがります。

SELECT CustomerID, CompanyName FROM Customers _
   WHERE CustomerID = 'ALFKI' UNION _
   SELECT 'database name' as dummy, name from master.sys.databases

 インジェクションの最後に付けられたコメント文字(--)により、元のSQLの一重引用符が削除され、新たな一重引用符とUNION SELECT文に置き換えられます。このUNION SELECT文が成功すると、サーバ上にあるすべてのデータベースのユーザーが表示されてしまいます。このとき、Webページには図3のような結果が表示されるでしょう。

図3 UNION SELECT文が成功すると、無害なWebページは悪意あるユーザーのスパイツールや破壊ツールに変わり果てる
図3 UNION SELECT文が成功すると、無害なWebページは悪意あるユーザーのスパイツールや破壊ツールに変わり果てる

 このような簡単な例であれば、修正する方法はいくつもあります。ドロップダウンだけを表示することもできますし、入力値を正規表現でフィルタリングして、DELETE FROM文、一重引用符およびSQLのコメント(--)など、害を及ぼす危険性のある不適当な値が入力されていないかを調べることもできます。また、LINQ to SQLを使用するという手もあります。

次のページ
LINQ to SQLによるSQLインジェクションの排除

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Paul Kimmel(Paul Kimmel)

CodeGuruのVB Todayのコラムニスト。オブジェクト指向プログラミングや.NETについてさまざまな書籍を執筆。『Professional DevExpress ASP.NET Controls』(Wiley刊)はAmazon.comおよび大型書店で好評発売中。『Teach Yourself the...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/3042 2008/10/07 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング