web-dev-qa-db-ja.com

SQLインジェクションを防ぐ良い方法は何ですか?

OJT会社のアプリケーション管理システムをプログラムする必要があります。フロントエンドはC#で、バックエンドはSQLで行われます。

今、私は以前にこの範囲のプロジェクトをやったことがありません。学校では、SQLに関する基本的なレッスンしかありませんでした。どういうわけか、私たちの先生は、SQLインジェクションについて完全に議論することに失敗しました。

とにかく私の質問は次のとおりです:C#でSQLインジェクションをどのように防ぐのですか?アプリケーションのテキストフィールドを適切にマスクして、指定された形式の入力のみを受け入れるようにすることで、漠然とそれができると思います。たとえば、電子メールのテキストボックスは「[email protected]」の形式である必要があります。このアプローチで十分でしょうか?または、.NETには、このようなものを処理する事前定義されたメソッドがありますか?テキストボックスにフィルターを適用して、メールアドレス形式または名前テキストボックスのみを受け入れ、特殊文字を受け入れないようにできますか?

36
LeonidasFett

SqlCommand とその パラメーターの子コレクション を使用することにより、SQLインジェクションのチェックのすべての苦痛があなたから取り除かれ、これらのクラスによって処理されます。

上記の記事の1つから抜粋した例を次に示します。

private static void UpdateDemographics(Int32 customerID,
    string demoXml, string connectionString)
{
    // Update the demographics for a store, which is stored  
    // in an xml column.  
    string commandText = "UPDATE Sales.Store SET Demographics = @demographics "
        + "WHERE CustomerID = @ID;";

    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        SqlCommand command = new SqlCommand(commandText, connection);
        command.Parameters.Add("@ID", SqlDbType.Int);
        command.Parameters["@ID"].Value = customerID;

        // Use AddWithValue to assign Demographics. 
        // SQL Server will implicitly convert strings into XML.
        command.Parameters.AddWithValue("@demographics", demoXml);

        try
        {
            connection.Open();
            Int32 rowsAffected = command.ExecuteNonQuery();
            Console.WriteLine("RowsAffected: {0}", rowsAffected);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
44
Oliver

私の答えはとても簡単です。

C#とSQLデータベース間の通信にはEntity Frameworkを使用します。これにより、SQLインジェクションに対して脆弱ではないパラメーター化されたSQL文字列が作成されます。

おまけとして、それも非常に簡単に操作できます。

7

SQLインジェクションは難しい問題になる可能性がありますが、それを回避する方法があります。 Linq2Entities、Linq2SQL、NHibrenateなどのORMを使用するだけで、リスクが軽減されます。ただし、SQLインジェクションの問題が発生することもあります。

SQLインジェクションの主なものは、ユーザーが制御する入力です(XSSと同様)。最も単純な例では、ユーザー名とパスワードを入力するログインフォームがある場合(これを行うだけのフォームはないことを願っています)。

SELECT * FROM Users WHERE Username = '" + username + "' AND password = '" + password + "'"

ユーザーがユーザー名に以下を入力した場合Admin '-データベースに対して実行すると、SQLステートメントは次のようになります。

SELECT * FROM Users WHERE Username = 'Admin' --' AND password = ''

この単純なケースでは、パラメータ化されたクエリ(ORMが行うこと)を使用すると、リスクがなくなります。また、あまり知られていないSQLインジェクション攻撃ベクトルの問題もあり、それはストアドプロシージャにあります。この場合、パラメーター化されたクエリまたはORMを使用しても、SQLインジェクションの問題が発生します。ストアドプロシージャには実行コマンドを含めることができ、それらのコマンド自体はSQLインジェクション攻撃を受けやすい可能性があります。

CREATE PROCEDURE SP_GetLogin @username varchar(100), @password varchar(100) AS
DECLARE @sql nvarchar(4000)
SELECT @sql = ' SELECT * FROM users' +
              ' FROM Product Where username = ''' + @username + ''' AND password = '''+@password+''''

EXECUTE sp_executesql @sql

したがって、この例では、パラメータ化されたクエリまたはORMを使用する場合でも、前の例と同じSQLインジェクションの問題が発生します。この例は馬鹿げているように見えますが、このようなものがどれほど頻繁に書かれているかについては驚くでしょう。

私の推奨事項は、ORMを使用してSQLインジェクションの問題が発生する可能性を即座に減らし、問題が発生する可能性のあるコードとストアドプロシージャを見つけて修正することです。 ADO.NET(SqlClient、SqlCommandなど)を直接使用することはお勧めしません。パラメーターを使用するのはどういうわけか安全ではないからではなく、遅延を取得してSQLの記述を開始する方がずっと簡単だからです文字列を使用して、パラメータを無視するだけのクエリ。 ORMSは、パラメーターを使用するよう強制するという素晴らしい仕事をしています。

次に、SQLインジェクションに関するOWASPサイトにアクセスします https://www.owasp.org/index.php/SQL_Injection になり、SQLインジェクションのチートシートを使用して、問題が発生する可能性のある問題を見つけて取り除くことができることを確認します。あなたのコードで発生します。 https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet 最後に、あなたとあなたの会社の他の開発者の間で、お互いのコードをレビューできる適切なコードレビューを実施すると言います。 SQLインジェクションやXSSなど。多くの場合、プログラマーはこの機能を見逃します。なぜなら、彼らは何らかの機能を急ぎ出そうとしていて、コードのレビューにあまり時間を費やさないからです。

7
nerdybeardo

入力を検証しようとしてSQLインジェクションを防ぐべきではありません。代わりに、その入力はデータベースに渡される前に適切にエスケープする必要があります。

入力をエスケープする方法は、データベースとのインターフェイスに使用しているテクノロジーに完全に依存します。ほとんどの場合、むき出しのSQL(できる限りハードに避ける必要があります)を記述しない限り、フレームワークによって自動的に処理されるため、無料で防弾保護を取得できます。

インターフェース技術が何であるかを正確に決定した後、この質問をさらに検討する必要があります。

4
Jon