首页 / 教程列表 / C#+ADO.NET数据库入门教程 / C#程序中使用ADO.NET时如何防止SQL注入攻击

C#程序中使用ADO.NET时如何防止SQL注入攻击

478 更新于: 2021-10-20 读完约需 4 分钟

概述

通过上一篇《什么是SQL注入攻击?》的介绍,我们对SQL注入攻击有了一定的了解和认识。知道了在写任何有用户输入的应用程序时均有可能发生SQL注入攻击的危险。

有危险我们就得防范,本文就为大家分享一些在C#&.NET(.NET Core)应用程序中通过ADO.NET访问SQL Server数据库时可用的防止SQL注入攻击的方法。

使用SQL参数

在C#&.NET应用程序中,如果通过ADO.NET操作SQL Server或者MySQL数据库,防止SQL注入攻击最好的方式是使用SQL参数,禁止直接使用字符串拼接SQL语句。

请看完整的字符串拼接的SQL语句与SQL参数化的关于SQL注入攻击的测试对比,示例代码如下:

using System;
using System.Data;
using System.Data.SqlClient;

namespace ConsoleApp1
{
    class Program
    {
        // 定义一个私有字段,存储数据库连接字符串信息(这里连接的是mssqllocaldb数据库,登录方式为Windows身份验证)
        private const string _connectionString = "Server=(localdb)\\mssqllocaldb;Integrated Security=true;Database=Demo";
        static void Main(string[] args)
        {
            // 1.正常的用户输入
            var familyName = "高";
            var email = "ostellinof0@sohu.com";
            var result1 = LoginWithSqlCombination(familyName, email);
            Console.WriteLine($"SQL拼接方式登录:{(result1 ? "成功" : "失败")}");
            var result2 = LoginWithSqlParameter(familyName, email);
            Console.WriteLine($"SQL参数方式登录:{(result2 ? "成功" : "失败")}");

            // 2.SQL注入攻击测试,将familyName修改成SQL注入攻击样式的字符串
            familyName = "高'--";
            result1 = LoginWithSqlCombination(familyName, email);
            Console.WriteLine($"SQL拼接方式登录(注入测试):{(result1 ? "成功" : "失败")}");
            result2 = LoginWithSqlParameter(familyName, email);
            Console.WriteLine($"SQL参数方式登录(注入测试):{(result2 ? "成功" : "失败")}");
            Console.ReadKey();
        }

        /// <summary>
        /// 方式一:使用SQL拼接的方式模拟用户登录的方法
        /// </summary>
        /// <param name="familyName"></param>
        /// <param name="email"></param>
        /// <returns>返回true表示用户登录成功</returns>
        static bool LoginWithSqlCombination(string familyName, string email)
        {
            // 1.实例化一个SQL Server的连接对象(这里使用using语句块,以自动释放连接资源)
            using SqlConnection connection = new SqlConnection(_connectionString);
            // 2.编写根据FamilyName和Email条件查询数据的SQL语句
            var commandText = $"SELECT * FROM Customer WHERE FamilyName='{familyName}' AND Email='{email}'";
            var da = new SqlDataAdapter(commandText, connection);
            var ds = new DataSet();
            da.Fill(ds);
            if (ds.Tables[0].Rows.Count > 0)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 方式二:使用SQL参数的方式模拟用户登录的方法
        /// </summary>
        /// <param name="familyName"></param>
        /// <param name="email"></param>
        /// <returns>返回true表示用户登录成功</returns>
        static bool LoginWithSqlParameter(string familyName, string email)
        {
            // 1.实例化一个SQL Server的连接对象(这里使用using语句块,以自动释放连接资源)
            using SqlConnection connection = new SqlConnection(_connectionString);
            // 2.编写根据FamilyName和Email条件查询数据的SQL语句
            var commandText = $"SELECT * FROM Customer WHERE FamilyName=@familyName AND Email=@email";
            // 3.实例化一个SqlCommand对象command
            var command = new SqlCommand(commandText, connection);

            /*
             * SqlCommand添加SQL参数的方式有两种:
             * 1.先调用Parameters.Add()添加SQL参数名,再用类似Parameters["@familyName"].Value = familyName;为SQL参数赋值
             * 2.用AddWithValue的方式向SQL参数添加email参数同时赋值
             * 示例如下
             */

            // 4.向command中添加@familyName SQL参数
            command.Parameters.Add("@familyName", SqlDbType.NVarChar);
            // 5.为@familyName参数赋值
            command.Parameters["@familyName"].Value = familyName;

            // 6.用AddWithValue的方式向SQL参数添加email参数同时赋值
            command.Parameters.AddWithValue("email", email);
            var da = new SqlDataAdapter(command);
            var ds = new DataSet();
            da.Fill(ds);
            if (ds.Tables[0].Rows.Count > 0)
            {
                return true;
            }
            return false;
        }
    }
}

运行结果如图:

从测试结果可以看到,使用SQL参数能有效防止SQL注入攻击。

SqlCommand添加SQL参数的方式有两种:
1.先调用Parameters.Add()添加SQL参数名,再用类似Parameters[“@familyName”].Value = familyName;为SQL参数赋值
2.用AddWithValue的方式向SQL参数添加email参数同时赋值

对用户输入加强验证

总体来说,防治SQL注入式攻击可以采用两种方法:

  • 一是加强对用户输入内容的检查与验证;
  • 二是强迫使用参数化语句来传递用户输入的内容。

在SQLServer数据库中,有比较多的用户输入内容验证工具,可以帮助管理员来对付SQL注入式攻击。测试字符串变量的内容,只接受所需的值。拒绝包含二进制数据、转义序列和注释字符的输入内容。这有助于防止脚本注入,防止某些缓冲区溢出攻击。

测试用户输入内容的大小和数据类型,强制执行适当的限制与转换。这即有助于防止有意造成的缓冲区溢出,对于防治注入式攻击有比较明显的效果。

如可以使用存储过程来验证用户的输入。利用存储过程可以实现对用户输入变量的过滤,在执行SQL语句之前,可以通过数据库的存储过程,来拒绝接纳一些特殊的符号。在不影响数据库应用的前提下,应该让数据库拒绝包含以下字符的输入。如分号分隔符,它是SQL注入式攻击的主要帮凶。

故始终通过测试类型、长度、格式和范围来验证用户输入,过滤用户输入的内容。这是防止SQL注入式攻击的常见并且行之有效的措施。

总结

在C#&.NET(.NET Core)的应用程序开发中,如果使用ADO.NET与SQL Server, MySQL等数据库进行交互时,请尽量使用SQL参数处理SQL语句中的变量,不要直接进行SQL字符串的拼接,否则会有很大的SQL注入风险。同时,对用户的输入内容加强验证。以达到更好的防止SQL注入的效果。

版权声明:本作品系原创,版权归码友网所有,如未经许可,禁止任何形式转载,违者必究。

发表评论

登录用户才能发表评论, 请 登 录 或者 注册