CS.SV.SQL_QUERY

セキュリティ脆弱性について SQL クエリをレビューします。

この規則は、文字列引数にユーザー入力が含まれていることを想定しています。ユーザー入力から作成された SQL コマンド文字列は、SQL インジェクション攻撃に対して脆弱です。SQL インジェクション攻撃では、悪意のあるユーザーは、基礎になるデータベースに損傷を与えたり、不正なアクセスを取得したりするための試みにおいて、クエリの設計を変更する入力を行います。

典型的な手法としては、SQL リテラル文字列の区切り文字である単一引用符またはアポストロフィ、SQL コメントを表す 2 つのダッシュ、および新しいコマンドが続くことを示すセミコロンの注入があります。ユーザー入力をクエリの一部にする必要がある場合は、有効性の順にリストされた次のいずれかを使用して、攻撃のリスクを軽減します。

  • ストアドプロシージャを使用する。
  • パラメーター化されたコマンド文字列を使用する。
  • コマンド文字列を作成する前に、型と内容の両方についてユーザー入力を検証する。

次の .NET Framework 型は、CommandText プロパティを実装するか、文字列引数を使用することで、プロパティを設定するコンストラクターを提供します。

  • System.Data.Odbc.OdbcCommand および System.Data.Odbc.OdbcDataAdapter
  • System.Data.OleDb.OleDbCommand および System.Data.OleDb.OleDbDataAdapter
  • System.Data.OracleClient.OracleCommand および System.Data.OracleClient.OracleDataAdapter
  • [System.Data.SqlServerCe.SqlCeCommand] および [System.Data.SqlServerCe.SqlCeDataAdapter]
  • System.Data.SqlClient.SqlCommand および System.Data.SqlClient.SqlDataAdapter

軽減と防止

この規則の違反を修正するには、パラメーター化されたクエリを使用します。

脆弱コード例

コピー
  using System;
  using System.Data;
  using System.Data.SqlClient;
  
  namespace SecurityLibrary
  {
     public class SqlQueries
     {
       public object UnsafeQuery(
          string connection, string name, string password)
       {
          SqlConnection someConnection = new SqlConnection(connection);
          SqlCommand someCommand = new SqlCommand();
          someCommand.Connection = someConnection;
 
          someCommand.CommandText = "SELECT AccountNumber FROM Users " +
             "WHERE Username='" + name + 
             "' AND Password='" + password + "'";
 
          someConnection.Open();
          object accountNumber = someCommand.ExecuteScalar();
          someConnection.Close();
          return accountNumber;
       }
 
       public object SaferQuery(
          string connection, string name, string password)
       {
          SqlConnection someConnection = new SqlConnection(connection);
          SqlCommand someCommand = new SqlCommand();
          someCommand.Connection = someConnection;
 
          someCommand.Parameters.Add(
             "@username", SqlDbType.NChar).Value = name;
          someCommand.Parameters.Add(
             "@password", SqlDbType.NChar).Value = password;
          someCommand.CommandText = "SELECT AccountNumber FROM Users "
             "WHERE Username=@username AND Password=@password";
 
          someConnection.Open();
          object accountNumber = someCommand.ExecuteScalar();
          someConnection.Close();
          return accountNumber;
       }
    }
 
    class MalaciousCode
    {
       static void Main(string[] args)
       {
          SqlQueries queries = new SqlQueries();
          queries.UnsafeQuery(args[0], "' OR 1=1 --", "anything");
          // Resultant query (which is always true):   
          // SELECT AccountNumber FROM Users WHERE Username='' OR 1=1
 
          queries.SaferQuery(args[0], "' OR 1 = 1 --", "anything");
          // Resultant query (notice the additional single quote character):  
          // SELECT AccountNumber FROM Users WHERE Username=''' OR 1=1 --' 
          //                                   AND Password='anything'
       }
    }
 }

この例は、規則に違反しているメソッド UnsafeQuery と、パラメーター化されたコマンド文字列を使用することで、規則を満たしているメソッド SaferQuery を示しています。