ASP.NET,C# 如何将 StringQuery 传递给自定义 SQL 命令

ASP.NET, C# How to Pass a StringQuery to a custom SQL Command

我有一个小问题,我有一个 ASP.NET Webforms 应用程序。我发送 url?id=XX 是我的数据库索引或 ID。

我有一个 C# class 文件用于 运行 我的 SQL 连接和查询。这是代码:

public DataTable ViewProduct(string id)
{
    try
    {
        string cmdStr = "SELECT * Products WHERE Idx_ProductId = " + id;

        DBOps dbops = new DBOps();
        DataTable vpTbl = dbops.RetrieveTable(cmdStr, ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString);
        return vpTbl;
    }
    catch (Exception e)
    {
        return null;
    }
}

所以你可以看到我的问题在于 string cmdStr = "SQL Query" + variable;

我通过 URL 传递我的索引或 ID,然后请求它并将其转换为字符串,然后使用 ViewProduct(productId).

我不知道用什么语法或如何将 id 添加到我的 C# 字符串 sql 查询中。我试过:

string cmdStr = "SELECT * Products WHERE Idx_ProductId = @0" + id;
string cmdStr = "SELECT * Products WHERE Idx_ProductId = {0}" + id;

还有我目前有的也无济于事。

Products.Idx_ProductId 是什么类型?

可能是字符串,您需要使用引号:"... = '" + id.Trim() + "'";

我非常确定这将是关于 C# 中参数化查询的一些规范问题的重复,但显然没有(请参阅 this)!

您应该参数化您的查询 - 如果不这样做,您 运行 有可能将一段恶意代码自身注入到您的查询中。例如,如果您当前的代码可以 运行 针对数据库,那么让该代码执行如下操作将是微不足道的:

// string id = "1 OR 1=1"
"SELECT * Products WHERE Idx_ProductId = 1 OR 1=1" // will return all product rows
// string id = "NULL; SELECT * FROM UserPasswords" - return contents of another table
// string id = "NULL; DROP TABLE Products" - uh oh
// etc....

ADO.NET 提供了非常简单的功能来参数化您的查询,而您的 DBOps class 肯定不会使用它(您正在传递一个构建的命令字符串)。相反,你应该这样做:

public DataTable ViewProduct(string id)
{
    try
    {
        string connStr = ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString;
        using (SqlConnection conn = new SqlConnection(connStr))
        {
            conn.Open();
            using (SqlCommand cmd = conn.CreateCommand())
            {
                // @id is very important here!
                // this should really be refactored - SELECT * is a bad idea
                // someone might add or remove a column you expect, or change the order of columns at some point
                cmd.CommandText = "SELECT * Products WHERE Idx_ProductId = @id";
                // this will properly escape/prevent malicious versions of id
                // use the correct type - if it's int, SqlDbType.Int, etc.
                cmd.Parameters.Add("@id", SqlDbType.Varchar).Value = id;
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    DataTable vpTbl = new DataTable();
                    vpTbl.Load(reader);
                    return vpTbl;
                }
            }
        }
    }
    catch (Exception e)
    {
        // do some meaningful logging, possibly "throw;" exception - don't just return null!
        // callers won't know why null got returned - because there are no rows? because the connection couldn't be made to the database? because of something else?
    }
}

现在,如果有人试图通过 "NULL; SELECT * FROM SensitiveData",它将被正确地参数化。 ADO.NET/Sql 服务器会将其转换为:

DECLARE @id VARCHAR(100) = 'NULL; SELECT * FROM SensitiveData';
SELECT * FROM PRoducts WHERE Idx_ProductId = @id;

这将 return 没有结果(除非你有一个 Idx_ProductId 实际上是那个字符串)而不是 return 第二个 SELECT 的结果。

补充阅读: