目录
一、数据库语句注入漏洞
以查询语句举例,在textbox文本框中输入查询内容执行数据库查询。
1、普通sql语句方式查询
代码:
private void btnSqlRead1_Click(object sender, EventArgs e)
{
try
{
//SqlConnection为建立和数据库连接得对象
using (SqlConnection conn = new SqlConnection("Data Source=127.0.0.1; Initial Catalog=MyTest;User=sa;Password=54085408"))
{
conn.Open(); //打开连接
//通过连接创建一个向数据数据库发送命令(Command)得对象SqlCommand
using (SqlCommand cmd = conn.CreateCommand())
{
//CommandText为要执行得sql语句
//cmd.CommandText = "select Age from tbl_student where Name='pan'";
cmd.CommandText = "select Age from tbl_student where Name='" + txtSqlInput.Text + "'";
using (SqlDataReader rd = cmd.ExecuteReader())
{
while (rd.Read())
{
int age = rd.GetInt32(0);
MessageBox.Show( age.ToString());
}
}
}
}
}
catch { }
}
界面
数据库
测试1:输入正常得查询字符
普通sql语句是怎么造成数据注入漏洞得
输入:pan
测试2:输入特殊得拼接字符
输入 :1' or '1'='1
发现将每一个结果都显示出来
原因:输入得1' or '1'='1字符和程序内部得SQL语句拼接形成了SQL语句,使用断点调试发现新得SQL语句变为:select Age from tbl_student where Name=' 1' or '1'='1'
因为or '1'='1'条件始终满足,所以while条件一直都满足,因此把数据库中所以得数据都查询了出来。
2、防注入漏洞的SQL查询
方法:将要查询的字段的使用符号 @。(数据库的表名、字段名或者其它特殊的在sql语句或者select旁边的字段也不能使用@)
代码
private void btnSqlRead2_Click(object sender, EventArgs e)
{
try
{
//SqlConnection为建立和数据库连接得对象
using (SqlConnection conn = new SqlConnection("Data Source=127.0.0.1; Initial Catalog=MyTest;User=sa;Password=54085408"))
{
conn.Open(); //打开连接
//通过连接创建一个向数据数据库发送命令(Command)得对象SqlCommand
using (SqlCommand cmd = conn.CreateCommand())
{
//CommandText为要执行得sql语句
//cmd.CommandText = "select Age from tbl_student where Name=@name or Age>@age";
//cmd.Parameters.Add(new SqlParameter("@age", 100));
//cmd.Parameters.AddWithValue("@name", txtSqlInput2.Text);
cmd.CommandText = "select Age from tbl_student where Name=@name";
cmd.Parameters.Add(new SqlParameter("@name", txtSqlInput2.Text));
using (SqlDataReader rd = cmd.ExecuteReader())
{
while (rd.Read())
{
int age = rd.GetInt32(0);
MessageBox.Show(age.ToString());
}
}
}
}
}
catch { }
}
界面
数据库
测试
(1)输入1' or '1'='1,查询不再将数据库中数据弹出
(2)输入pan,查询出结果
其它语句如:
insert into ...... values(@name,@age)
delete .......where Id=@id
二、DataSet离线数据集
SqlDataReader是连接相关的,SqlDataReader中的查询结果并不是放到程序中的,而是在数据库服务器中,SqlDataReader只是相当于放了一个指针(游标),只能读取当前游标指向的行,一旦连接断开就不能再读取。这样做的好处就是无论查询结果有多少条,对程序占用的内存都几乎没有影响。
SqlDataReader对于小数据量的数据来说带来的只有麻烦。ADO.NET中提供了数据集的机制,将查询结果填充到本地内存中,这样连接断开、服务器断开都不影响数据的读取。数据集的好处是降低数据库服务器压力、编程也简单。
测试代码:
private void btnDataSetRead_Click(object sender, EventArgs e)
{
try
{
//SqlConnection为建立和数据库连接得对象
using (SqlConnection conn = new SqlConnection("Data Source=127.0.0.1; Initial Catalog=MyTest;User=sa;Password=54085408"))
{
conn.Open(); //打开连接
//通过连接创建一个向数据数据库发送命令(Command)得对象SqlCommand
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "select * from tbl_student where Age<@age";
cmd.Parameters.Add(new SqlParameter("@age", 100));
//SqlDataAdapter是一个帮我们把SqlCommand查询结果填充到DataSet中的类
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
//DataSet相当于本地的一个复杂集合List<...>
DataSet dataset = new DataSet();
adapter.Fill(dataset); //执行cmd,并且把SqlCommand查询结果填充到DataSet
DataTable table = dataset.Tables[0]; //dataset可以有很多个表
DataRowCollection rows = table.Rows;
for(int i=0;i<rows.Count;i++)
{
DataRow row = rows[i];
int age = (int)row["Age"];
string name = (string)row["Name"];
string comment = (string)row["Comment"];
MessageBox.Show(name + "," + age.ToString() + "," + comment);
}
}
}
}
catch { }
}
数据库数据
程序运行测试
依次跳出各个查询结果
三、连接字符串放到配置文件中
1、配置文件添加和编辑
将连接数据库的用户名、密码、数据库ip地址等放到配置文件中,方便用户在使用的时候方便修改。新创建的winform程序中自动添加App.config文件。如果没有的话,手动添加。
(1)手动添加配置文件
(2)双击打开配置文件
(3)修改配置文件,编译运行。
(4) 用户在使用时,在根目录下打开配置文件修改
(4) 修改程序工程中的,工程之间复制或者拷贝。然后工程再重新编译、生成
2、配置文件字符串在程序中使用
(1)在引用中添加程序集System.Configuration
(2)添加按钮事件程序,将配置文件中的字符串读出来
程序
using System.Configuration;
private void btnTestConnectString_Click(object sender, EventArgs e)
{
string connString = ConfigurationManager.ConnectionStrings["dbConnstr"].ConnectionString;
MessageBox.Show(connString);
}
运行结果
(3)修改上一个DataSet程序
修改前代码
private void btnDataSetRead_Click(object sender, EventArgs e)
{
try
{
//SqlConnection为建立和数据库连接得对象
using (SqlConnection conn = new SqlConnection("Data Source=127.0.0.1; Initial Catalog=MyTest;User=sa;Password=54085408"))
{
conn.Open(); //打开连接
//通过连接创建一个向数据数据库发送命令(Command)得对象SqlCommand
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "select * from tbl_student where Age<@age";
cmd.Parameters.Add(new SqlParameter("@age", 100));
//SqlDataAdapter是一个帮我们把SqlCommand查询结果填充到DataSet中的类
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
//DataSet相当于本地的一个复杂集合List<...>
DataSet dataset = new DataSet();
adapter.Fill(dataset); //执行cmd,并且把SqlCommand查询结果填充到DataSet
DataTable table = dataset.Tables[0]; //dataset可以有很多个表
DataRowCollection rows = table.Rows;
for(int i=0;i<rows.Count;i++)
{
DataRow row = rows[i];
int age = (int)row["Age"];
string name = (string)row["Name"];
string comment = (string)row["Comment"];
MessageBox.Show(name + "," + age.ToString() + "," + comment);
}
}
}
}
catch { }
}
修改后代码
private void btnTestConnectString_Click(object sender, EventArgs e)
{
try
{
string connString = ConfigurationManager.ConnectionStrings["dbConnstr"].ConnectionString;
//SqlConnection为建立和数据库连接得对象
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open(); //打开连接
//通过连接创建一个向数据数据库发送命令(Command)得对象SqlCommand
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "select * from tbl_student where Age<@age";
cmd.Parameters.Add(new SqlParameter("@age", 100));
//SqlDataAdapter是一个帮我们把SqlCommand查询结果填充到DataSet中的类
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
//DataSet相当于本地的一个复杂集合List<...>
DataSet dataset = new DataSet();
adapter.Fill(dataset); //执行cmd,并且把SqlCommand查询结果填充到DataSet
DataTable table = dataset.Tables[0]; //dataset可以有很多个表
DataRowCollection rows = table.Rows;
for (int i = 0; i < rows.Count; i++)
{
DataRow row = rows[i];
int age = (int)row["Age"];
string name = (string)row["Name"];
string comment = (string)row["Comment"];
MessageBox.Show(name + "," + age.ToString() + "," + comment);
}
}
}
}
catch { }
}
测试
将生成的Debug程序拷贝到虚拟机中的win7系统环境下运行,config中修改ip地址
工程代码
https://download.csdn.net/download/panjinliang066333/85153786
创作不易,请多多支持