65.9K
CodeProject 正在变化。 阅读更多。
Home

SQL 注入简介

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.08/5 (22投票s)

2009 年 3 月 26 日

CPOL

3分钟阅读

viewsIcon

72408

这就是为什么我们必须编写存储过程并从网页和表单中删除SQL代码的原因。

引言

每次我参与一个新项目,并恰巧继承它时,我总能在网页中发现SQL代码,以及未捕获的输入。 好吧,其中一些应用程序在内部使用,而另一些则向外部客户提供。 一位程序员争论在网页中编写SQL语句是多么危险。 在这篇短文中,我将解释为什么这是一种不好的编程习惯,或者如果您不捕获输入或在网页上编写SQL,这对您的用户来说是危险的。 因为这会导致SQL注入攻击。 什么是SQL注入?

背景

维基百科说,SQL注入是一种代码注入技术,它利用在安全漏洞,该漏洞发生在数据库层的应用程序中。 当用户输入未正确过滤字符串字面量中嵌入的转义字符SQL语句时,或者用户输入不是强类型时,并且由此意外地执行,就会出现该漏洞。 它是更普遍的一类漏洞的一个实例,这些漏洞可能发生在任何将编程或脚本语言嵌入到另一种语言中的时候。 SQL注入攻击也称为SQL插入攻击。[1]

Using the Code

我们将在文章中使用多处注释,并且将使用 C# 作为我们的语言。

Start

让我们以我在某个在线目录中看到的客户在线购物应用程序的代码为例。 代码看起来像这样,代码写得非常接近这样

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }

    protected void  Show_Data(String strssearch)
    {
        String strcon = 
            WebConfigurationManager.ConnectionStrings["MYSTRING"].ConnectionString;

        SqlConnection con = new SqlConnection(strcon);
        String tsql = "select * from dbo.memyself where fname = '" + strssearch + "'";
        SqlCommand cmd = new SqlCommand(tsql, con);
        con.Open();
        SqlDataReader reader = cmd.ExecuteReader();
       
        GridView1.DataSource = reader;
        GridView1.DataBind();
        reader.Close();
        con.Close();

    }

    protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
    {
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        Show_Data(txtsearch.Text);
    }
}

并且ASPX页面类似于

<%@ Page Language="C#" AutoEventWireup="true" 
         CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>SQL Injection Example</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        <asp:TextBox ID="txtsearch" runat="server"></asp:TextBox>
&nbsp;
        <asp:Button ID="Button1" runat="server" 
             onclick="Button1_Click" Text="Search" />
        <br />
    
    </div>
    <asp:GridView ID="GridView1" runat="server" 
           CellPadding="4" ForeColor="#333333" 
           GridLines="None" Height="169px" 
           onselectedindexchanged="GridView1_SelectedIndexChanged" 
           Width="396px">
        <RowStyle BackColor="#FFFBD6" ForeColor="#333333" />
        <FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
        <PagerStyle BackColor="#FFCC66" ForeColor="#333333" 
                       HorizontalAlign="Center" />
        <SelectedRowStyle BackColor="#FFCC66" Font-Bold="True" ForeColor="Navy" />
        <HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
        <AlternatingRowStyle BackColor="White" />
    </asp:GridView>
    <asp:Label ID="lblMessage" runat="server"></asp:Label>
    </form>
</body>
</html>

当您运行该应用程序时,它会向您显示类似这样的内容

PIC1.JPG

现在,当程序员看到他可以搜索到我时,他可能很高兴 :),但是现在这样做很危险。 让我们注入上面的应用程序。

SQL注入开始

在上面的示例中,不良用户(黑客)可能会尝试篡改SQL语句。 通常,不良用户尝试这样做的主要原因是他们收到一条错误消息,该消息将公开表和数据库的名称。 正如您在上面的代码中看到的那样,错误处理尚未完成,并且将显示低级别消息,该信息将被用来执行针对您数据库的其他恶意语句,如果这是一个在线购物网站,则客户的信用卡信息可能会被泄露。 现在,让我们注入上面的代码。 输入以下文本

“Vuyiswa' OR '1' = '1”

pic2.JPG

糟糕,它给出的比应该的还多。 这带来了Dave的信息,而应该只带来vuyiswa的信息。 我的意思是,用户可以在您的文本框上添加SQL语句,并返回比客户预期看到的更多的内容,而这可能是其他人的信用卡信息。 这还没完。 恶意用户甚至可以插入注释并运行额外的代码。 (在Oracle中,数据库注释使用(;)完成,在MySQL中使用(#)代码。)他甚至可以使用批处理命令来执行SQL命令。

让我们看看这个。 输入以下内容

Vuyiswa' ; truncate table dbo.Customers --

pic3.JPG

这里发生了什么? 表中的数据被删除了,我是说所有的数据。 让我们详细地看一下。

Vuyiswa' ; truncate table dbo.memyself --

使用“;”,您可以启动另一行。 所有这些都将被执行。 现在,如果您检查您的表,您将找不到任何数据。

解决方案

为了克服这个问题,需要参数化的存储过程和更多的输入验证。 可以像这样创建一个存储过程

CREATE PROC prc_search
(
@FNAME varchar(20)
)
AS
SELECT * FROM DBO.MEMYSELF WHERE FNAME = @FNAME

我们的函数应该像这样

protected void  Show_Data(String strssearch)
{
    String strcon = 
       WebConfigurationManager.ConnectionStrings["MYSTRING"].ConnectionString;

    SqlConnection con = new SqlConnection(strcon);
    SqlCommand cmd = new SqlCommand();
    cmd.CommandText = "dbo.prc_search";
    cmd.Parameters.Add("@FNAME", SqlDbType.VarChar, 20).Value = strssearch;
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Connection = con;
    SqlDataReader reader =null;

    try
    {
        con.Open();
        reader = cmd.ExecuteReader();
    }
    catch (SqlException ex)
    {
        lblMessage.Text = ex.Message.ToString();
    }
  
    if (reader.HasRows)
    {
        GridView1.DataSource = reader;
        GridView1.DataBind();
        reader.Close();
        con.Close();
    }
    else
    {
        lblMessage.Text = "There are no Records Available";
    }
}

现在,如果您再次进行注入测试,您将看到用户无法再次运行SQL命令。 我添加了一个标签来显示捕获的异常,并将其命名为lblMessage

结论

我只截断了表。 我不知道恶意用户会对这些数据做什么。 如果这是一个在线购物网站,我不知道。 有成千上万的站点是利用此漏洞构建的,请相信我,每天都有恶意用户在寻找这些站点。

感谢阅读!

© . All rights reserved.