【C#】SQLインジェクションを防ぐ!変数を安全にクエリに埋め込む正しい方法を解説!

スポンサーリンク

※ この記事にはアフィリエイトリンクが含まれます

C#でデータベースとやり取りする際、こんなふうに思ったことはありませんか?

「ユーザーが入力した値をSQLに入れて検索したい」
「変数を使ってINSERTやUPDATEをしたい」

プログラムからデータベースに命令を出すなら、変数をクエリに埋め込むというのは避けて通れません。でも、ここでひとつだけ、気をつけてほしいことがあります。

それは、「やり方を間違えると、思わぬバグやセキュリティの穴につながる」ということ。

実際、SQLに変数をそのまま文字列で組み込んでしまうと、SQLインジェクションと呼ばれる攻撃の対象になってしまうことがあります。これは、プログラムに悪意のあるSQL文を紛れ込ませることで、データが抜き取られたり、最悪の場合、削除されたりするような非常に危険なものです。

ですが、ご安心ください。

C#では、きちんと「安全に変数を埋め込む」ための方法が用意されています。それが、パラメータ化クエリという考え方です。

この記事では、次のことを丁寧に解説していきます。

  • やってはいけないNGな書き方と、その理由
  • 安全で正しいSQL文の書き方(実例つき)
  • より効率的に書くためのちょっとした工夫

これからSQLを使っていく方にも、すでに使っているけれど「なんとなく」でやっていた方にも、ぜひ知っていただきたい内容になっています。

それでは、実際にコードを見ながら進めていきましょう。

C#は、業務系のシステムやWindowsアプリ開発など、企業現場で広く使われている言語です。独学でもある程度学べますが、「しっかりとしたカリキュラムで基礎から学びたい」「開発経験を積みたい」と考える方も多いのではないでしょうか。

そんな方におすすめなのが、未経験からエンジニア転職を目指せる「DMM WEBCAMP エンジニア転職です。

C#に特化しているわけではありませんが、企業でよく使われるJavaやWeb技術と並行して、.NET系技術を扱う現場を視野に入れた学び方も可能です。

文字列連結でクエリを書くとどうなる?

さて、ここでありがちなコードの例をひとつご紹介します。もしかしたら、あなたもこんなふうに書いたことがあるかもしれません。

string userName = "tanaka";
string sql = "SELECT * FROM Users WHERE Name = '" + userName + "'";

ぱっと見、とてもわかりやすいコードですよね。
文字列をつなげて、userName の値をSQL文に直接埋め込んでいます。

でも――これは絶対にやってはいけません。

なぜかというと、この書き方には深刻なセキュリティリスクがあるからです。
それが「SQLインジェクション」と呼ばれる問題です。

たとえば、次のような悪意ある文字列を変数 userName に入力されたとしましょう。

' OR '1'='1

すると、生成されるSQL文はこうなります。

SELECT * FROM Users WHERE Name = '' OR '1'='1'

このSQL、よく見るとすべてのユーザーが取得されてしまう内容になっているのがわかります。
'1'='1' は常に真(true)になる条件なので、ユーザー名に関係なく、全レコードが返ってきてしまうんです。

さらに悪質なケースでは、削除系のクエリを挿入される可能性もあります。

'; DROP TABLE Users; --

これが通ってしまえば、Usersテーブルそのものが削除されてしまう可能性も……!

実際、こうした攻撃で情報漏洩やデータ破壊が発生した事例は、少なくありません。

「動くからOK」ではなく「安全かどうか」で判断を

このように、文字列を直接つなげてSQLを作るのは、非常に危険な行為です。
たとえテスト環境でうまく動いていたとしても、ユーザーの入力を扱う本番環境では致命的な穴になります。

だからこそ、C#でSQLを書くときは、「安全に変数を埋め込む」方法を選ぶ必要があります。

では、どう書けば安全なのか?
次のセクションで、正しい方法――「パラメータ化クエリ」について解説していきます。

パラメータ化されたクエリを使おう

危険な書き方を見ていただいたところで、ここからは正しい方法「パラメータ化クエリ」を解説していきます。

C#では SqlCommand を使って、SQLに変数を安全に渡すことができます。しかも、やり方は思ったより簡単です。

SqlCommand とパラメータの基本形

たとえば、特定のユーザー名で情報を取得する処理は、次のように書けます。

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    string sql = "SELECT * FROM Users WHERE Name = @Name";

    using (SqlCommand command = new SqlCommand(sql, connection))
    {
        command.Parameters.AddWithValue("@Name", userName);

        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                // レコード処理
            }
        }
    }
}

ポイントはここです。

  • SQL文内では @Name のようにパラメータ名を使う。
  • 実際の値は command.Parameters.AddWithValue("@Name", userName) で安全に渡す。

このようにすることで、ユーザーの入力がそのままSQL文に混入することを防ぎ、SQLインジェクションを確実に回避できます。

AddWithValue の注意点と型を指定する方法

AddWithValue は手軽ですが、ひとつ注意点があります。

C#の型とSQL Server側の型がうまく一致しない場合、意図しない動作になることがあるのです。
たとえば、数値が文字列として処理されたり、インデックスが効かずにパフォーマンスが悪化することも。

そのため、型を明示的に指定する方法も知っておきましょう。

command.Parameters.Add("@Name", SqlDbType.NVarChar, 50).Value = userName;

この書き方では、

  • @NameNVarChar(50) として扱われる
  • 型が明確なので、SQL Server側も最適な方法で処理してくれる

ポイント

  • SqlDbType はSQL Serverで使うデータ型を指定する列挙体です。
  • 必ずしもすべての場面で型指定が必要なわけではありませんが、「検索が遅い」「うまくヒットしない」といったときはこの方法が有効です。

安全性とパフォーマンス、両方を大切にするなら、パラメータ化+型指定は基本スキルとして身につけておきたいところです。

INSERTやUPDATEにも変数を使う方法

ここまでで、「パラメータ化クエリ」の基本的な使い方はご理解いただけたかと思います。

ですが、実際の開発では「SELECT文」だけでは終わりませんよね。
ユーザー情報を追加したり、既存のデータを更新したりする――そんな場面でも、もちろん安全な変数の埋め込みが必要です。

ここでは、INSERT文とUPDATE文におけるパラメータ化の使い方をご紹介します。

INSERT文で変数を使う

たとえば、ユーザー名と年齢をデータベースに追加する場合、次のように記述します。

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    string sql = "INSERT INTO Users (Name, Age) VALUES (@Name, @Age)";

    using (SqlCommand command = new SqlCommand(sql, connection))
    {
        command.Parameters.AddWithValue("@Name", name);
        command.Parameters.AddWithValue("@Age", age);
        command.ExecuteNonQuery();
    }
}
  • @Name, @Age にそれぞれの値を渡すだけ。
  • ExecuteNonQuery() は、SELECT以外の処理(INSERT、UPDATE、DELETEなど)で使用します。

UPDATE文で変数を使う

今度は、指定された名前のユーザーの年齢を更新するケースを見てみましょう。

string sql = "UPDATE Users SET Age = @Age WHERE Name = @Name";

using (SqlCommand command = new SqlCommand(sql, connection))
{
    command.Parameters.AddWithValue("@Age", newAge);
    command.Parameters.AddWithValue("@Name", name);
    command.ExecuteNonQuery();
}

このように、UPDATE文でも完全に同じ要領でパラメータを使えます。

  • WHERE句にもパラメータを使うことで、条件も安全に扱える。
  • 書き方を統一することで、ミスやセキュリティリスクも減らせます。

DELETE文でも同じ考え方でOK

補足ですが、DELETE文でもまったく同じように書けます。

string sql = "DELETE FROM Users WHERE Name = @Name";
command.Parameters.AddWithValue("@Name", name);

どんなSQL文でも、「変数は絶対に文字列連結せず、パラメータで渡す」というルールを守ること。
これが、安全で信頼できるアプリケーションの第一歩です。

まとめ

C#でSQLに変数を埋め込みたいとき、つい文字列をそのままつなげてしまいがちですが、それは非常に危険な書き方です。

なぜなら、ユーザーの入力値をそのままSQLに反映させることで、SQLインジェクションという深刻なセキュリティリスクを生んでしまうからです。

本記事では、そんなリスクを避けるためのパラメータ化クエリの使い方を、以下のポイントに分けてご紹介しました。

  • SqlCommand@パラメータ を使った安全なSQLの書き方
  • AddWithValue() の基本と、型を明示するより安全な方法
  • INSERT、UPDATE、DELETEなど、あらゆるSQL文への応用
  • Dapperのような軽量ORMを使えば、さらに効率化も可能

覚えておいてほしいのは、「動けばOKではなく、安全に動くかどうか」がこれからの開発ではより大切になるということ。

SQLインジェクションは初心者だけでなく、ベテランでもうっかりやってしまうほど、身近で見落とされやすい問題です。
だからこそ、今このタイミングで「安全な書き方」を身につけたあなたは一歩リードしています。

ぜひ、この記事で学んだことを、明日からのコードに活かしてくださいね。

C#は、堅牢でスケーラブルなアプリケーションを構築できる力強い言語です。将来的にエンジニアとしてキャリアを築きたい方にとっては、非常に価値ある選択肢と言えるでしょう。

もし「本格的に学んで、いずれはエンジニアとして働きたい」とお考えなら、転職サポートが充実した「DMM WEBCAMP エンジニア転職」のようなスクールで学ぶのもおすすめです。

C#
スポンサーリンク
なんくるをフォローする

コメント

タイトルとURLをコピーしました