我有一个 ASP.net C# 站点。我用这段代码将其中一个 ListView 提供给它,它就工作了:
protected void BindData()
{
string forwardedSearchText = Request.QueryString["SearchText"];
string forwardedSearchColumn = Convert.ToString(Session["SearchTitle"]);
string strsql = "Select TbSoore.IdSoore, TbSoore.NameSoore, TbAye.NumberAye, TbAye.IdAye, TbAye.TextAye, TbAye.TextTarjome From TbAye INNER JOIN TbSoore ON TbAye.IdSoore = TbSoore.IdSoore Where FreeText((" + forwardedSearchColumn + "),N' " + forwardedSearchText + "')";
DataTable dt = new DataTable();
using (SqlConnection con = new SqlConnection(strcon))
{
using
(SqlCommand cmdSQL = new SqlCommand(strsql, con))
{
con.Open();
ListViewSearchResults.DataSource = cmdSQL.ExecuteReader();
ListViewSearchResults.DataBind();
}
}
}
现在我想将查询字符串样式更改为更好的安全性:
$@"Select TbSoore.IdSoore, TbSoore.NameSoore, TbAye.NumberAye, TbAye.IdAye, TbAye.TextAye, TbAye.TextTarjome From TbAye INNER JOIN TbSoore ON TbAye.IdSoore = TbSoore.IdSoore Where FreeText(({forwardedSearchColumn}),N' @forwardedSearchText ')";
因此将
BindData()
更改为:
protected void BindData()
{
string forwardedSearchText = Request.QueryString["SearchText"];
string forwardedSearchColumn = Convert.ToString(Session["SearchTitle"]);
string strsql = $@"Select TbSoore.IdSoore, TbSoore.NameSoore, TbAye.NumberAye, TbAye.IdAye, TbAye.TextAye, TbAye.TextTarjome From TbAye INNER JOIN TbSoore ON TbAye.IdSoore = TbSoore.IdSoore Where FreeText(({forwardedSearchColumn}),N' @forwardedSearchText ')";
DataTable dt = new DataTable();
using (SqlConnection con = new SqlConnection(strcon))
{
using
(SqlCommand cmdSQL = new SqlCommand(strsql, con))
{
cmdSQL.Parameters.Add("@forwardedSearchText", SqlDbType.NVarChar).Value = forwardedSearchText;
con.Open();
ListViewSearchResults.DataSource = cmdSQL.ExecuteReader();
ListViewSearchResults.DataBind();
}
}
}
但这不起作用。我没有收到任何错误,但表是空的。
有人可以帮助我吗?
一个很好的例子,说明如何在代码中格式化 SQL 文本,并且不让它扭曲页面,确保在阅读代码时,您可以轻松地看到所有文本。
我会考虑使用视图,甚至更好的存储过程,这样就可以消除由于难以读取内联 SQL 而导致的此错误。
SQL 参数不使用也不需要引号。
我建议这样:
protected void BindData()
{
string forwardedSearchText = Request.QueryString["SearchText"];
string forwardedSearchColumn = Convert.ToString(Session["SearchTitle"]);
string strsql =
$@"Select TbSoore.IdSoore, TbSoore.NameSoore, TbAye.NumberAye, TbAye.IdAye, TbAye.TextAye,
TbAye.TextTarjome From TbAye
INNER JOIN TbSoore ON TbAye.IdSoore = TbSoore.IdSoore
Where FreeText({forwardedSearchColumn},@forwardedSearchText)";
DataTable dt = new DataTable();
using (SqlConnection con = new SqlConnection(strcon))
{
using
(SqlCommand cmdSQL = new SqlCommand(strsql, con))
{
cmdSQL.Parameters.Add("@forwardedSearchText", SqlDbType.NVarChar).Value = forwardedSearchText;
con.Open();
ListViewSearchResults.DataSource = cmdSQL.ExecuteReader();
ListViewSearchResults.DataBind();
}
}
}
此外,如果 ListView 在数据绑定期间需要使用完整行(例如通常用于格式化每行),则向 ListView 提供读取器将不允许在绑定过程中使用完整数据行。
所以,我建议:
cmdSQL.Parameters.Add("@forwardedSearchText", SqlDbType.NVarChar).Value = forwardedSearchText;
con.Open();
DataTable dt = new DataTable();
dt.Load(cmdSQL.ExecuteReader());
ListViewSearchResults.DataSource = dt;
ListViewSearchResults.DataBind();
通过上述方法,我们减少了搜索词的字符串连接,但仍然存在注入漏洞。
问题当然是SearchColumn仍然是一个串联表达式,但更糟糕的是t-sql不允许列名作为参数。
如果该列只能是一列,那么我建议对该列进行硬编码,甚至为给定的列名称引入 switch case 语句。
如果列数是可变的(并且可以多于一列),那么至少确保此选择是某种列表框,或用户不输入列名称的其他类型的 UI。
如上所述,这些列名称的串联仍然存在安全风险。
因此,我将确保您的 UI 的列选择不允许列名称使用自由格式(文本框输入)。