本文主要介绍PostgreSQL数据库中NpgsqlParameter的用法。(MySql中MySqlParameter的用法与之类似)
首先,为什么要用NpgsqlParameter?那就要先分析直接执行SQL语句的风险了。
执行一个查询语句,目的是在表ModelInfo中查询ModelName等于某一值的行数目,该值由用户输入。代码如下:
static void Main(string[] args)
{
var connStr = "Server=localhost;Port=5433;Username=postgres;Password=123456;Database=Testpg100";
using (NpgsqlConnection con = new NpgsqlConnection(connStr))
{
string modelname = Console.ReadLine();
string sql = "select count(*) from \"ModelInfo\" where \"ModelName\" = '" + modelname + "'";
NpgsqlCommand cmd = new NpgsqlCommand(sql, con);
con.Open();
int num = Convert.ToInt32(cmd.ExecuteScalar());
Console.WriteLine("count:" + num);
}
}
用户输入为harris时,查询字符串如下:
select count(*) from "ModelInfo" where "ModelName" = 'Harris'
执行结果为:1,即:只有一条记录中“ModelName”的值为“Harris”。
上述是正常的做法,程序员喜欢的这样做的用户。但总有用户不走寻常路,他们不会老老实实按照程序员的期待输入一个ModelName的值,他们想输入的更多,如:
harris' or "ModelId"='
这是凌乱的输入表示什么?仅仅是ModelName的值的吗?看看它生成的查询字符串吧!
select count(*) from "ModelInfo" where "ModelName" = 'harris' or "ModelId"=''
是不是很神奇,生成的查询字符串不仅是可执行的,而且有了完全不同的含义。它不仅查询ModelName等于Harris的记录,也查询了ModelId等于' '的记录,这完全超出了程序的预期。
精巧的构造输入的SQL可以生成更厉害的语句,从而得到关于数据库中更多的信息,这些信息有可能是不应该提供给用户的,敏感信息的泄露会造成的损失不可预计。这种通过构造SQL获取数据库敏感信息的做法,有一个专业术语—SQL注入。
如何避免SQL注入?使用NpgsqlParameter,而不是直接执行SQL语句!
static void Main(string[] args)
{
var connStr = "Server=localhost;Port=5433;Username=postgres;Password=123456;Database=Testpg10";
using (NpgsqlConnection con = new NpgsqlConnection(connStr))
{
string modelname = Console.ReadLine();
string sql = "select count(*) from \"ModelInfo\" where \"ModelName\" = @name";
NpgsqlCommand cmd = new NpgsqlCommand(sql, con);
cmd.Parameters.Add(new NpgsqlParameter("@name", modelname));
con.Open();
int num = Convert.ToInt32(cmd.ExecuteScalar());
Console.WriteLine(num);
}
}