San*_*ndy 104 sql sql-server sql-injection
我很擅长使用数据库.现在我可以写SELECT
,UPDATE
,DELETE
,和INSERT
命令.但我看过很多我们喜欢写的论坛:
SELECT empSalary from employee where salary = @salary
Run Code Online (Sandbox Code Playgroud)
...代替:
SELECT empSalary from employee where salary = txtSalary.Text
Run Code Online (Sandbox Code Playgroud)
为什么我们总是喜欢使用参数以及如何使用它们?
我想知道第一种方法的用途和好处.我甚至听说过SQL注入,但我并不完全理解它.我甚至不知道SQL注入是否与我的问题有关.
Cha*_*evy 119
当数据库与程序接口(如桌面程序或网站)结合使用时,使用参数有助于防止SQL注入攻击.
在您的示例中,用户可以通过制作语句直接在数据库上运行SQL代码txtSalary
.
例如,如果他们要写0 OR 1=1
,那么执行的SQL就是
SELECT empSalary from employee where salary = 0 or 1=1
Run Code Online (Sandbox Code Playgroud)
所有的奖励都将被退回.
此外,用户可以对您的数据库执行更糟糕的命令,包括删除它如果他们写道0; Drop Table employee
:
SELECT empSalary from employee where salary = 0; Drop Table employee
Run Code Online (Sandbox Code Playgroud)
employee
然后将删除该表.
在您的情况下,看起来您正在使用.NET.使用参数非常简单:
C#
string sql = "SELECT empSalary from employee where salary = @salary";
using (SqlConnection connection = new SqlConnection(/* connection info */))
using (SqlCommand command = new SqlCommand(sql, connection))
{
var salaryParam = new SqlParameter("salary", SqlDbType.Money);
salaryParam.Value = txtMoney.Text;
command.Parameters.Add(salaryParam);
var results = command.ExecuteReader();
}
Run Code Online (Sandbox Code Playgroud)
VB.NET
Dim sql As String = "SELECT empSalary from employee where salary = @salary"
Using connection As New SqlConnection("connectionString")
Using command As New SqlCommand(sql, connection)
Dim salaryParam = New SqlParameter("salary", SqlDbType.Money)
salaryParam.Value = txtMoney.Text
command.Parameters.Add(salaryParam)
Dim results = command.ExecuteReader()
End Using
End Using
Run Code Online (Sandbox Code Playgroud)
编辑2016-4-25:
根据George Stocker的评论,我将示例代码更改为不使用AddWithValue
.此外,通常建议您将IDisposable
s 包装在using
语句中.
Nul*_*ion 70
你是对的,这与SQL注入有关,这是一个漏洞,允许一个appleioius用户对你的数据库执行任意语句.这个旧时代最喜欢的XKCD漫画说明了这个概念:
在您的示例中,如果您只是使用:
var query = "SELECT empSalary from employee where salary = " + txtSalary.Text;
// and proceed to execute this query
Run Code Online (Sandbox Code Playgroud)
您对SQL注入持开放态度.例如,假设有人输入txtSalary:
1; UPDATE employee SET salary = 9999999 WHERE empID = 10; --
1; DROP TABLE employee; --
// etc.
Run Code Online (Sandbox Code Playgroud)
当您执行此查询时,它将执行a SELECT
和a UPDATE
或者DROP
他们想要的任何内容.将--
在年底只需注释掉查询的其余部分,如果你串联后什么这将是在进攻中非常有用txtSalary.Text
.
正确的方法是使用参数化查询,例如(C#):
SqlCommand query = new SqlCommand("SELECT empSalary FROM employee
WHERE salary = @sal;");
query.Parameters.AddWithValue("@sal", txtSalary.Text);
Run Code Online (Sandbox Code Playgroud)
有了它,您可以安全地执行查询.
有关如何避免使用其他几种语言的SQL注入的参考,请查看由SO用户维护的网站bobby-tables.com.
除了其他答案外,还需要补充一点,参数不仅有助于防止sql注入,而且可以提高查询性能。SQL Server缓存参数化的查询计划,并在重复执行查询时重用它们。如果未参数化查询,则如果查询文本不同,则sql server将在每个查询(带有某些排除项)执行时编译新计划。
在我第一次去两年后,我正在重蹈覆辙……
为什么我们更喜欢参数?SQL 注入显然是一个重要原因,但可能是我们暗中渴望回到 SQL作为一种语言。字符串文字中的 SQL 已经是一种奇怪的文化实践,但至少您可以将您的请求复制并粘贴到管理工作室。使用宿主语言条件和控制结构动态构造的 SQL,当 SQL 具有条件和控制结构时,只是 0 级野蛮。您必须在调试或跟踪中运行您的应用程序,以查看它生成的 SQL。
不要仅仅停留在参数上。一直使用QueryFirst(免责声明:我写的)。您的 SQL 存在于 .sql 文件中. 您可以在美妙的 TSQL 编辑器窗口中对其进行编辑,并对表和列进行语法验证和智能感知。您可以在特殊评论部分分配测试数据,然后单击“播放”以在窗口中直接运行您的查询。创建参数就像在 SQL 中放入“@myParam”一样简单。然后,每次保存时,QueryFirst 都会为您的查询生成 C# 包装器。您的参数以强类型弹出,作为 Execute() 方法的参数。您的结果在 IEnumerable 或强类型 POCO 列表中返回,这些类型是从查询返回的实际模式生成的。如果您的查询未运行,您的应用程序将无法编译。如果您的数据库架构更改并且您的查询运行但某些列消失,则编译错误指向代码中的行试图访问丢失的数据。还有许多其他优点。为什么要以其他方式访问数据?