SQL注入(SQL Injection)攻击原理与防御措施

SQL是一种代码注入技术,可使攻击者修改应用程序向数据库提供的查询。 迄今为止,最常见和最严重的应用 程序安全威胁总是隐藏在与数据库有某些连接的网络应用 程序中。 通过这种 SQL 注入,攻击者可以绕过登录程序,获取、更改甚至更新数据库,执行管理程序,或进行其他变种操作。

了解 SQL 注入

要解释什么 是 SQL 注入,就必须了解 SQL 的一些基本原理。 事实上,它已成为处理和虚拟操作这些数据库的通用语言。 它用于查询、插入、更新和删除数据库记录,几乎所有网络应用程序都使用它来访问数据库;它可以在 PHP、 Python、 Java、 PIA Utah VPN 和 . NET中编写 。

在网络应用程序中,用户需要通过表单、搜索框或 URL 等方式在系统中输入信息,所有这些输入信息通常都用于动态构建 SQL 查询。 这是因为,如果用户输入的 SQL 查询字符串没有经过适当的检查和消毒,攻击者就可以通过在预期的 SQL 查询字符串中注入恶意 SQL 语句来改变 SQL 查询字符串的性质。

SQL 注入示例

举例来说,在登录一个典型的网络应用程序时,用户需要输入用户名和密码。 用来验证凭据的实际 SQL 查询如下:

复制代码
SELECT * FROM users WHERE username = 'user_input' AND password = 'password_input';

如果应用程序直接使用用户的输入值而不进行任何消毒处理,攻击者就可以输入类似这样的内容。

  • 用户名' OR '1'='1
  • 密码' OR '1'='1

由此产生的 SQL 查询将是

复制代码
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '' OR '1'='1';

这样,攻击者就能绕过验证码,畅通无阻地访问系统

大家看这段代码,其实特别简单,就是我在没有账号和密码的时候,用这段代码来打开数据库,这样如果弹出"已经被sql注入" ,那么就代表我通过代码层的注入。

大家一眼就可以看出来我的用户名是1' or '1'='1 密码也是,结果是_:_

那么说明了,你的数据库危险了,因为这个用户名和密码根本不存在。

那么这就是一个简单的后台身份验证绕过了漏洞。

验证绕过漏洞就是'or'='or'后台绕过漏洞,利用的就是AND和OR的运算规则,从而造成后台脚本逻辑性错误。

后台查询语句是: sql='select admin from user_info where userid=' '' & txtuser.text & ''' & ' and pwd=' & ''' & txtpassword.text & ''', 那么我使用1'or '1'='1(这里1可是其他的一些数)来做用户名密码的话,那么查询就变成了: select admin from user_info where userid='1'or '1'='1' and pwd='1'or '1'='1'

这样的话,根据运算规则,这里一共有4个查询语句,那么查询结果就是 假or真and假or真,先算and 再算or,最终结果为真,这样就可以进到后台了。

这种漏洞存在必须要有2个致命的条件。

我们可以从这里入手,进行防护。

阻止 SQL 注入的方法

第一种:这种查询是账号和密码是在一个sql语句中,如果一旦分开就不会被注入。

sql="select * from admin where username='"&username&'&"passwd='"&passwd&'

如果一旦账号密码是分开查询的,先查帐号,再查密码,这样的话就没有办法了。

我解决的代码时这样的:

txtsql = "select * from user_Info where userid= '" & TxtUserName.Text & "'"

Set mrc = ExecuteSQL(txtsql, msgtext)

If mrc.EOF Then

MsgBox "没有这个用户,请重新输入用户名!", vbOKOnly + vbExclamation, "警告"

TxtUserName.SetFocus

Else

If Trim(mrc.Fields(1)) = Trim(TxtPassword.Text) Then

OK = True

mrc.Close

Me.Hide

UserName = Trim(TxtUserName.Text)

Else

MsgBox "密码错误,请重新输入!", vbOKOnly + vbExclamation, "警告"

TxtPassword.SetFocus

TxtPassword.Text = ""

End If

第二种方法:如果加密了,一旦被MD5加密或者其他加密方式加密的,那么密码就不会是完整的,那么就不存在这样的错误了。

如果一个用户提供的字段并非一个强类型,或者没有实施类型强制,就会发生这种形式的攻击。当在一个SQL语句中使用一个数字字段时,如果程序员没有检查用户输入的合法性(是否为数字型)就会发生这种攻击。例如:

statement := "SELECT * FROM user_info WHERE userid = " & id_text & ";"

从这个语句可以看出,id_text是一个与"userid"字段有关的数字。不过,如果终端用户选择一个字符串,就绕过了对转义字符的需要。例如,将id_text设置为:1;DROP TABLE users,它会将"users"表从数据库中删除,SQL语句变成:SELECT * FROM User_Info WHERE UserID= 1;DROP TABLE users;好滴,那么你的数据库就会遭受不可恢复的删除。

第三种方法:那么我们就可以通过传参的方法,来解决这中sql注入:

如果自己编写防注代码,一般是先定义一个函数,再在里面写入要过滤的关键词,如select ; "";from;等,这些关键词都是查询语句最常用的词语,一旦过滤了,那么用户自己构造提交的数据就不会完整地参与数据库的操作。

Function SafeRequest(ParaName,ParaType)

'--- 传入参数 ---

'ParaName:参数名称-字符型

'ParaType:参数类型-数字型(1表示以上参数是数字,0表示以上参数为字符)

Dim ParaValue

ParaValue=Request(ParaName)

If ParaType=1 then

If not isNumeric(ParaValue) then

Response.write "参数" & ParaName & "必须为数字型!"

Response.end

End if

Else

ParaValue=replace(ParaValue,"'","''")

End if

SafeRequest=ParaValue

End function

为防止 SQL 注入,您需要遵循编码准则、正确管理数据库并实施安全措施。以下是一些降低 SQL 注入风险的策略:

1.使用预处理语句(参数化查询)

预处理语句确保用户输入纯粹作为数据处理,而不是作为 SQL 命令的组成部分。

这种方法允许数据库区分 SQL 查询结构和数据本身,确保任何输入都不能修改查询结构。

例如,在 PHP 中使用 PDO(PHP 数据对象):

复制代码
$stmt = $pdo-&gt;prepare('SELECT * FROM users WHERE username = :username AND password = :password');<br>
$stmt-&gt;execute(['username' =&gt; $username_input, 'password' =&gt; $password_input]);

在本例中,:username:password是用户输入的占位符,它们会被用户提供的实际值安全地替代。数据库引擎将输入作为纯数据处理,因此任何恶意输入都不会造成危害。

2.输入验证和消毒

始终对用户输入进行验证和消毒,确保其符合预期格式。例如,如果输入应该是一个整数,那么在处理之前就应该检查数据类型。

在 Python 中,您可能会使用正则表达式来验证输入:

复制代码
import re<br>
<br>
def validate_input(user_input):<br>
    if re.match("^[a-zA-Z0-9_]+$", user_input):<br>
        return True<br>
    else:<br>
        return False

该功能只允许使用字母数字字符和下划线,从而降低了 SQL 注入的风险。

3.使用 ORM(对象关系映射)库

ORM 库抽象了数据库交互,允许开发人员使用编程语言语法与数据库交互,而不是直接使用 SQL 查询。

通过自动安全地处理查询构造,这一抽象本质上可防止 SQL 注入。

例如,在Django(一种 Python 网络框架)中,你不需要编写原始 SQL,而是像这样与数据库交互:

复制代码
user = User.objects.get(username=user_input)

Django 的 ORM 可自动处理查询结构并防止 SQL 注入。

4.限制数据库权限

只授予应用程序必要的最低数据库权限。如果应用程序不需要删除记录,就不要授予它DELETE权限。这种最小权限原则可以减少攻击者发现 SQL 注入漏洞时造成的破坏。

5.使用网络应用防火墙WAF

WAF 可以在恶意输入到达应用程序之前将其过滤掉,从而检测并阻止常见的 SQL 注入尝试。WAF 是一个额外的安全层,是对编码实践的补充。

6.错误处理和报告

避免向最终用户显示详细的数据库错误信息。相反,在服务器端记录这些错误,并向用户显示通用错误信息。这种做法可以防止攻击者深入了解你的数据库结构。

在 .NET 中,您可以使用 try-catch 块来处理 SQL 错误:

复制代码
try<br>
{<br>
    // Database operations<br>
}<br>
catch (SqlException ex)<br>
{<br>
    // Log error details<br>
    Logger.Log(ex);<br>
    // Show a generic message to the user<br>
    Response.Write("An error occurred. Please try again later.");<br>
相关推荐
岁岁种桃花儿9 小时前
MySQL从入门到精通系列:InnoDB记录存储结构
数据库·mysql
蜜獾云9 小时前
oracle查询所有的表名和注释
oracle
jiunian_cn10 小时前
【Redis】hash数据类型相关指令
数据库·redis·哈希算法
冉冰学姐10 小时前
SSM在线影评网站平台82ap4(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm框架·在线影评平台·影片分类
知识分享小能手11 小时前
SQL Server 2019入门学习教程,从入门到精通,SQL Server 2019数据库的操作(2)
数据库·学习·sqlserver
爬山算法12 小时前
Hibernate(84)如何在DevOps流程中使用Hibernate?
oracle·hibernate·devops
踩坑小念12 小时前
秒杀场景下如何处理redis扣除状态不一致问题
数据库·redis·分布式·缓存·秒杀
萧曵 丶13 小时前
MySQL 语句书写顺序与执行顺序对比速记表
数据库·mysql
Wiktok14 小时前
MySQL的常用数据类型
数据库·mysql
曹牧14 小时前
Oracle 表闪回(Flashback Table)
数据库·oracle