App_Code SQL Inject/Select
App_Code SQL Inject/Select
如果可能的话,我需要一些指导
说明
我在 App_Code 中有一个主要的 project.cs 文件,其中包含主要功能。其中一个函数是 SQL_Inject,它将数据插入数据库。
然后我有多个页面同时从多台客户端计算机使用此功能。
问题
我想要的答案是,这是一种安全的选择方法吗?或者我应该在每个 .cs 页面上单独创建一个新连接。
Reason/Problem
这成为一个问题的原因是,我们目前是一家小公司,但正在成长。由于 SQL 连接仍然打开,页面发生崩溃。我担心这是因为同时试图建立两个连接。我不确定这是问题所在还是其他原因。
//GLOBAL DECLARATIONS
//DB CONNECTIONS - retrieve from config file
public static string ConProjectms = System.Configuration.ConfigurationManager.ConnectionStrings["conProject"].ConnectionString;
//DB CONNECT TO SQL
public static SqlConnection SqlConn = new SqlConnection();
public static SqlCommand SqlCmd = new SqlCommand();
public static SqlDataReader SqLdr;
public static string SqlStr;
public static string ConnString;
public static void SqlInject(string query, string dataBase)
{
SqlConn.ConnectionString = ConProjectms;
//Set the Connection String
SqlConn.Open();
//Open the connection
SqlCmd.Connection = SqlConn;
//Sets the Connection to use with the SQL Command
SqlCmd.CommandText = query;
//Sets the SQL String
SqlCmd.ExecuteNonQuery();
//put Data
SqlClose();
}
public static void SqlClose()
{
if (SqlConn.State != ConnectionState.Open) return;
SqlConn.Close();
SqlCmd.Parameters.Clear();
}
App_Code 中的数据库代码没有理由不工作。这听起来更像是你的连接池不能很好地工作。查看连接字符串、IIS 设置和数据库的性能。如果由于某种原因无法使用连接池,那么查询的 运行 时间就会成为问题。
SQL 可以同时处理多个连接。但是,您的代码很可能同时被两个客户端 运行 使用,并且他们将使用 相同的连接 而不是两个单独的连接。那是坏事#1。
SQL 服务器在连接池方面做得非常出色——我假设其他数据库也有类似的功能。在这样的世界中,您不应该尝试保留和重复使用任何 data-related 对象 - 而是根据需要创建它们,并且当 SQL 发现您正在使用它之前创建的连接时自从释放后,它将使用它。您无需执行任何奇怪的操作即可获得此功能。
考虑到这一点,您的静态对象应该大部分消失,并且您的 SQLInject 方法可能看起来像这样:
public static void SqlInject(string query, string dataBase)
{
var connectionString =
System
.Configuration
.ConfigurationManager
.ConnectionStrings["conProject"]
.ConnectionString;
using ( var connection = new SqlConnection( connectionString ) )
{
connection.Open( );
using ( var command = connection.CreateCommand( ) )
{
command.CommandText = query;
command.CommandType = CommandType.Text;
command.ExecuteNonQuery( );
}
}
}
请注意,您不必担心关闭连接本身; using
块处理打开的活动对象的配置。这主要是人们从 c#
直接 SQL
的方式。顺便说一句,你的代码和我的代码都不使用 dataBase 参数。也许您应该用它来编辑基本连接字符串??
但是等等 - 还有更多!
说了这么多,既然你提出了安全问题,你应该知道这根本不是安全代码 - 你的或我的。 SqlInject 可能是一个好名字,因为它几乎允许 query
参数中的任何内容(顺便说一句,如果您正在执行 ExecuteNonQuery,那么 query
可能不是一个好名字)。
你最好允许参数到已知语句库(可能是存储过程),验证这些参数,并使用 SQL 注入攻击缓解来参数化你的已知语句(查找该短语和你会发现大量的例子和建议)。
只是为了讨厌,这里有一个你可能会考虑的框架:
public static void SqlInject(string commandName, params[] object commandArgs )
{
//--> no point in going on if we got no command...
if ( string.IsNullOrEmpty( commandName ) )
throw new ArgumentNullException( nameof( commandName ) );
var connectionString =
System
.Configuration
.ConfigurationManager
.ConnectionStrings["conProject"]
.ConnectionString;
using ( var connection = new SqlConnection( connectionString ) )
{
connection.Open( );
using ( var command = connection.CreateCommand( ) )
{
command.CommandType = CommandType.Text;
command.CommandText = "select commandText from dbo.StatementRepository where commandName = @commandName";
command.Parameters.AddWithValue( "@commandName", commandName );
var results = command.ExecuteScalar( );
if ( results != null && results != DbNull.Value )
{
//--> calling a separate method to validate args, that returns
//--> an IDictionary<string,object> of parameter names
//--> and possibly modified arguments.
//--> Let this validation method throw exceptions.
var validatedArgs = ValidateArgs( commandName, commandArgs );
command.Parameters.Clear( );
command.CommandText = query;
foreach( var kvp in validatedArgs )
{
command.Parameters.AddWithValue( kvp.Key, kvp.Value );
}
command.ExecuteNonQuery( );
}
else
{
throw new InvalidOperationException( "Invalid command" );
}
}
}
}
我没有尝试编写实际的参数验证方法,因为这都包含在您的应用程序逻辑中……但我想让您了解如何获得 更安全状态。
如果可能的话,我需要一些指导
说明 我在 App_Code 中有一个主要的 project.cs 文件,其中包含主要功能。其中一个函数是 SQL_Inject,它将数据插入数据库。
然后我有多个页面同时从多台客户端计算机使用此功能。
问题 我想要的答案是,这是一种安全的选择方法吗?或者我应该在每个 .cs 页面上单独创建一个新连接。
Reason/Problem 这成为一个问题的原因是,我们目前是一家小公司,但正在成长。由于 SQL 连接仍然打开,页面发生崩溃。我担心这是因为同时试图建立两个连接。我不确定这是问题所在还是其他原因。
//GLOBAL DECLARATIONS
//DB CONNECTIONS - retrieve from config file
public static string ConProjectms = System.Configuration.ConfigurationManager.ConnectionStrings["conProject"].ConnectionString;
//DB CONNECT TO SQL
public static SqlConnection SqlConn = new SqlConnection();
public static SqlCommand SqlCmd = new SqlCommand();
public static SqlDataReader SqLdr;
public static string SqlStr;
public static string ConnString;
public static void SqlInject(string query, string dataBase)
{
SqlConn.ConnectionString = ConProjectms;
//Set the Connection String
SqlConn.Open();
//Open the connection
SqlCmd.Connection = SqlConn;
//Sets the Connection to use with the SQL Command
SqlCmd.CommandText = query;
//Sets the SQL String
SqlCmd.ExecuteNonQuery();
//put Data
SqlClose();
}
public static void SqlClose()
{
if (SqlConn.State != ConnectionState.Open) return;
SqlConn.Close();
SqlCmd.Parameters.Clear();
}
App_Code 中的数据库代码没有理由不工作。这听起来更像是你的连接池不能很好地工作。查看连接字符串、IIS 设置和数据库的性能。如果由于某种原因无法使用连接池,那么查询的 运行 时间就会成为问题。
SQL 可以同时处理多个连接。但是,您的代码很可能同时被两个客户端 运行 使用,并且他们将使用 相同的连接 而不是两个单独的连接。那是坏事#1。
SQL 服务器在连接池方面做得非常出色——我假设其他数据库也有类似的功能。在这样的世界中,您不应该尝试保留和重复使用任何 data-related 对象 - 而是根据需要创建它们,并且当 SQL 发现您正在使用它之前创建的连接时自从释放后,它将使用它。您无需执行任何奇怪的操作即可获得此功能。
考虑到这一点,您的静态对象应该大部分消失,并且您的 SQLInject 方法可能看起来像这样:
public static void SqlInject(string query, string dataBase)
{
var connectionString =
System
.Configuration
.ConfigurationManager
.ConnectionStrings["conProject"]
.ConnectionString;
using ( var connection = new SqlConnection( connectionString ) )
{
connection.Open( );
using ( var command = connection.CreateCommand( ) )
{
command.CommandText = query;
command.CommandType = CommandType.Text;
command.ExecuteNonQuery( );
}
}
}
请注意,您不必担心关闭连接本身; using
块处理打开的活动对象的配置。这主要是人们从 c#
直接 SQL
的方式。顺便说一句,你的代码和我的代码都不使用 dataBase 参数。也许您应该用它来编辑基本连接字符串??
但是等等 - 还有更多!
说了这么多,既然你提出了安全问题,你应该知道这根本不是安全代码 - 你的或我的。 SqlInject 可能是一个好名字,因为它几乎允许 query
参数中的任何内容(顺便说一句,如果您正在执行 ExecuteNonQuery,那么 query
可能不是一个好名字)。
你最好允许参数到已知语句库(可能是存储过程),验证这些参数,并使用 SQL 注入攻击缓解来参数化你的已知语句(查找该短语和你会发现大量的例子和建议)。
只是为了讨厌,这里有一个你可能会考虑的框架:
public static void SqlInject(string commandName, params[] object commandArgs )
{
//--> no point in going on if we got no command...
if ( string.IsNullOrEmpty( commandName ) )
throw new ArgumentNullException( nameof( commandName ) );
var connectionString =
System
.Configuration
.ConfigurationManager
.ConnectionStrings["conProject"]
.ConnectionString;
using ( var connection = new SqlConnection( connectionString ) )
{
connection.Open( );
using ( var command = connection.CreateCommand( ) )
{
command.CommandType = CommandType.Text;
command.CommandText = "select commandText from dbo.StatementRepository where commandName = @commandName";
command.Parameters.AddWithValue( "@commandName", commandName );
var results = command.ExecuteScalar( );
if ( results != null && results != DbNull.Value )
{
//--> calling a separate method to validate args, that returns
//--> an IDictionary<string,object> of parameter names
//--> and possibly modified arguments.
//--> Let this validation method throw exceptions.
var validatedArgs = ValidateArgs( commandName, commandArgs );
command.Parameters.Clear( );
command.CommandText = query;
foreach( var kvp in validatedArgs )
{
command.Parameters.AddWithValue( kvp.Key, kvp.Value );
}
command.ExecuteNonQuery( );
}
else
{
throw new InvalidOperationException( "Invalid command" );
}
}
}
}
我没有尝试编写实际的参数验证方法,因为这都包含在您的应用程序逻辑中……但我想让您了解如何获得 更安全状态。