ASP.NET的SQL注入攻击与预防 使用SQLServer

前言

本文通过一个以用户登录为例的示例项目,讲述了SQL注入攻击与预防。

示例项目使用了VS2017与SqlServer2008r2,采用WebAPI的架构。

下面让我们从头开始。

开始

Step.1 新建数据库表

在Test数据库下新建users表,含有3个字段(id,uid,pwd). 并添加一条数据。

ASP.NET的SQL注入攻击与预防 使用SQLServer

Step.2 新建ASP.NET项目

打开 VS2017,选择【文件】->【新建】 ->【项目】,并在【新建项目】 窗口中选择 Visual C# -> Web -> ASP.NET Web应用程序, 点击确定。

ASP.NET的SQL注入攻击与预防 使用SQLServer

在弹出窗口中选择空模板,并添加 Web API的核心引用,点击确定。

ASP.NET的SQL注入攻击与预防 使用SQLServer

在解决方案资源管理器中,打开App_Start/WebApiConfig.cs,在routeTemplate中添加action段:

routeTemplate: "api/{controller}/{action}/{id}",

打开Web.config,添加connectionString[name=‘db’],用来连接数据库。

选择 【项目】 -> 【管理nuget程序包】->下载安装Jquery.

在解决方案资源管理器中,右键点击Controllers文件夹,依次选择【添加】->【控制器】->【Web API 2控制器-空】,点击添加,取名为UserController . 将UserController.cs中的代码替换为下面代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Data;
using System.Data.SqlClient;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Configuration;

namespace SQLTest.Controllers
{
    public class UserController : ApiController
    {
        public JObject Login([FromBody]JObject requestJson)
        {
            JObject respJson = new JObject();
            string uid = requestJson["uid"].ToString();
            string pwd = requestJson["pwd"].ToString();
            string conStr = ConfigurationManager.ConnectionStrings["db"].ToString();
            SqlConnection con = new SqlConnection(conStr);
            con.Open();
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = con;
            cmd.CommandText = $"select * from users where uid='{uid}' and pwd='{pwd}'";
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataTable dt = new DataTable();
            da.Fill(dt);
            if (dt.Rows.Count == 1) respJson.Add("success", "true");
            else respJson.Add("success", "false");
            return respJson;
        }

    }
}

添加Html页面,并将代码替换为如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    uid:<input id="uid" type="text" /><br />
    pwd:<input id="pwd" type="text" /><br />
    <input type="button" id="submit" value="login" onclick="login()"/><br />

    <script src="Scripts/jquery-3.3.1.min.js"></script>
    <script>
        function login() {
            var postData = {
                uid: $("#uid").val(),
                pwd: $("#pwd").val()
            };
            var url = "api/User/Login";
            $.post(url, postData, function (resp) {
                if (resp.success == "true") {
                    alert("login ok");
                }
                else {
                    alert("err");
                }
            });
        }
    </script>
</body>
</html>

至此,项目新建完毕。解决方案目录如下:

ASP.NET的SQL注入攻击与预防 使用SQLServer

Step.3 Sql注入攻击示例

F5运行项目。

首先进行正常登录。uid输入wufan, pwd输入qwe123后,点击login按钮:

ASP.NET的SQL注入攻击与预防 使用SQLServer

可以看到登录正常。

下面我们模拟正常情况下的密码错误。将pwd填入qwe1234,点击login按钮,可以看到登录失败。

ASP.NET的SQL注入攻击与预防 使用SQLServer

接下来进行Sql注入攻击。在uid处填入wufan’-- ,pwd仍然使用上面的错误密码,点击login按钮后,可以看到竟然也登录成功了。
ASP.NET的SQL注入攻击与预防 使用SQLServer

这就是sql注入攻击。恶意添加单引号来提前关闭sql语句中的uid参数,并使用两个杠将接下来的东西都注释掉,使得实际查询的sql语句变成:

select * from users where uid='wufan'-- and pwd='qwe1234'

两个杠后面的代码被注释后,实际sql为:

select * from users where uid='wufan'

在这种情况下,密码随便填也能登录成功。

Step.4 Sql注入的预防

第一种方法,就是在前后端对用户输入进行校验,比如不允许输入特殊字符,或者将用户输入的特殊字符进行转义等。

第二种方法,是使用 SqlCommand.Parameters . 将UserController.cs/Login方法改为下面代码即可。

public JObject Login([FromBody]JObject requestJson)
{
    JObject respJson = new JObject();
    string uid = requestJson["uid"].ToString();
    string pwd = requestJson["pwd"].ToString();
    string conStr = ConfigurationManager.ConnectionStrings["db"].ToString();
    SqlConnection con = new SqlConnection(conStr);
    con.Open();
    SqlCommand cmd = new SqlCommand();
    cmd.Connection = con;
    cmd.CommandText = "select * from users where [email protected] and [email protected]";
    cmd.Parameters.Add("@uid",SqlDbType.NVarChar,50);
    cmd.Parameters.Add("@pwd",SqlDbType.NVarChar, 50);
    cmd.Parameters["@uid"].Value = uid;
    cmd.Parameters["@pwd"].Value = pwd;
    SqlDataAdapter da = new SqlDataAdapter(cmd);
    DataTable dt = new DataTable();
    da.Fill(dt);
    if (dt.Rows.Count == 1) respJson.Add("success", "true");
    else respJson.Add("success", "false");
    return respJson;
}

运行项目后,重复Step3中的sql注入攻击,可以看到登录失败,符合预期。

ASP.NET的SQL注入攻击与预防 使用SQLServer

结束