SQL注入

SQL注入

SQL注入是因为后台SQL语句拼接了用户的输入,而且Web应用程序对用户输入数据的合法性没有判断和过滤,前端传入后端的参数是攻击者可控的,攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作。比如查询、删除,增加,修改数据等等,如果数据库的用户权限足够大,还可以对操作系统执行操作。

SQL注入可以分为平台层注入和代码层注入。前者由不安全的数据库配置或数据库平台的漏洞所致;后者主要是由于程序员对输入未进行细致地过滤。SQL注入是针对数据库、后台、系统层面的攻击!

mysql中注释符:# 、/**/ 、 --

一、分类

  1. 依据注入点类型分类

    • 数字类型的注入

    • 字符串类型的注入

    • 搜索型注入

  2. 依据提交方式分类

    • GET注入

    • POST注入

    • COOKIE注入

    • HTTP注入(XFF注入、UA注入、REFERER注入)

      XFF:X-Forwarded-ForXFF)是用来识别通过HTTP代理负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。

      UA:用户代理(User Agent,简称 UA),是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。

      REFERER:HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器该网页是从哪个页面链接过来的,服务器因此可以获得一些信息用于处理。

  3. 依据获取信息的方式分类

    • 基于布尔的盲注

    • 基于时间的盲注

    • 基于报错的注入

    • 联合查询注入

    • 堆查询注入(可同时执行多条语句)

二、判断是否存在SQL注入

  1. 工具扫描:网站漏扫工具、AWVS、AppScan、OWASP-ZAP、Nessus等

  2. 手动测试:

    • 单双引号、括号;进行组合测试,看是否报错

    • 对于数字型:?id=3-1 ?id=2#

      如果显示的是?id=2时的正常页面,可判断注入点是数字型注入;如果返回不正常,则可判断非数字型注入

    • 对于字符型:?id=2a ?id=2'#

      Mysql 中,等号两边如果类型不一致,会发生强制类型转换。当数字与字符串进行比较时, 首先先将字符串转换成数字,然后再进行比较。

    • 对于布尔盲注:

      盲注:就是在服务器没有错误回显时完成的注入攻击。服务器没有错误回显,对于攻击者来说缺少了非常重要的信息,所以攻击者必须找到一个方法来验证注入的SQL语句是否得到了执行。

      ?id=1' and '1 ?id=1' and 'a

      这里没有使用注释符号进行后面的单引号闭合,使用的是手工单引号闭合

      或者, ?id=1' and 1=1# ?id=1' and 1=2#

      两者的页面截然不同,一个正常回显,一个没有回显的话,就可判断是布尔盲注。

    • 对于时间盲注:

      ?id=1' and sleep(3)#

      在MySQL中,有一个Benchmark() 函数,它是用于测试性能的。 Benchmark(count,expr) ,这个函数执行的结果,是将表达式 expr 执行 count 次 。

      因此,利用benchmark函数,可以让同一个函数执行若干次,使得结果返回的时间比平时要 长,通过时间长短的变化,可以判断注入语句是否执行成功。这是一种边信道攻击,这个技巧在 盲注中被称为Timing Attack,也就是时间盲注。

  3. 常见SQL注入功能点

    只要是存在数据库交互的地方都有可能出现 SQL 注入。

    常出现在 登录页面、订单页面、文章或新闻展示页面、修改密码页面(二次注入)、涉及获 取 HTTP 头(XFF等)的功能点等。

三、MySQL注入

  1. 必备

    1. 元数据库 information_schema

      元数据库 information_schema 中:
         
      存放数据库信息的表:schemata
      schemata 表中
      字段 schema_name 存放所有数据库名;
         
      存放表信息的表:tables
      tables 表中
      字段 table_name 存放所有表名
      字段 table_schema 存放所有表所在的数据库名;
         
      存放所有字段信息的表:columns
      columns 表中
      字段 column_name 存放所有字段名,
      字段 table_name 存放所有字段所在的表名,
      字段 table_schema 存放所有字段所在的数据库名;
    2. 语句分类

      1.DQL(数据查询语言):查询语句,所有的 select 语句
      2.DML(数据操作语言):insert , delete , update , 对表中的 数据 进行 增删改
      3.DDL(数据定义语言):create , drop , alter 对表 结构 的 增删改
      4.TCL(事务控制语言):commit 提交数据,rollback 回滚数据 Transaction
      5.DCL(数据控制语言):grant 授权,revoke 撤销权限等
    3. 基本语句

      # 查库:
      show databases;
      select schema_name from information_schema.schemata;
      # 建库:
      create database + 库名;
      # 删库:
      drop database + 库名;
      # 进入数据库:
      use + 库名;
      # 查表:
      show tables;
      select table_name from information_schema.tables where table_schema='security'
      select table_name from information_schema.tables where table_schema=database
      # 查列:
      select * from users;
      select column_name from information_schema.columns where table_name='users'
      # 查字段:
      select username,password from security.users;
    4. 基本函数

      #数据库安装、路径,用户 信息
      version(); Mysql 数据库版本
      database(); 当前 数据库名
      user(); 数据库的用户名
      current_user(); 当前用户名
      session_user(); 连接到数据库的用户名
      system_user(); 系统用户名
      @@datadir(); 数据库文件的存放路径
      @@version_compile_os; 操作系统版本
      @@basedir; 数据库的安装目录
      #字符串长度、截取
      length(); 返回字符串的长度
      substring(a,b,c); 截取字符串
      substr(a,b,c);
      mid(a,b,c);
      三个参数:a.截取的字符串 b.截取的起始位置 c.长度
      left(a,b); 从左侧截取a的前b位,正确返回1,错误返回0
      #字符串配对连接
      concat(a,0x5e,b); 字符串配对连接
      concat_ws('~',A,B); 含有分隔符的连接字符串
      group_concat(); 将字符串连接为一个组,可将不同列分到同一行中
      #字符串特殊处理
      ord(); 返回ASCII码
      ascii('a'); 将字母 a 转换为ascii值
      rand(); 返回0~1之间的随机浮点数
      round(); 返回最近的整数值
      md5(); 返回MD5值
      hex(); 将字符串转换为十六进制
      unhex(); hex()的反向操作
      floor(x); 返回不大于x的最大整数
      load_file(); 读取文件,返回文件内容作为一个字符串
      sleep(a); 沉睡a秒
      if(true,t,f); 判断语句为true ,执行第一个,否则第二个
      find_in_set(); 返回字符串在字符串列表中的位置
      benchmark(); 指定语句执行的次数
      name_const(); 返回表作为结果
    5. 导入数据

      当希望导入一个 较大 的文件或者是想要批量的执行sql语句时,可以使用 mysql 中的 source 使用方法:source + 文件路径(直接拖拽)

  2. 语句

    # insert
    insert into 表名(字段名1,字段名2,字段名3......) values(值1,值2,值3......);
    # delete
    delete from 表名 where 条件;//可回滚
    对于大表:
    truncate table 表名;//不可回滚,将会永久丢失
    # update
    update 表名 set 字段名1=值1,字段名2=值2,......where 条件;
    # select
    select 字段1,字段2,...... from + 表名 where + 条件;
    # between and
    select * from users where id between 2 and 8;
    select * from users where id >=2 and id <=8;
    # in not in
    select password from users where id not in(5,8);
    指查找出 id不等于5 和 id不等于8 的用户的密码
    注:不是 5~8,in之后不是一个区间
    # like
    1.% 代表任意多个字符
    2._ 代表任意一个字符
    select username from users where username like '%b%';
    指查找出用户名中带有字母b的用户名
    select username from users where username like '_a%';
    指查找出用户名中带第二个字母为a的用户名
    select username from users where username like '%b';
    指查找出用户名中带最后一个字母为b的用户名
    select username from users where username like '%\_%';
    指查找出用户名中带有下划线_的用户名
    注:特殊字符需要转义
    # order by
    select username from users order by 字段名;
    注:默认为升序排列
    指定升序:asc
    select username from users order by 字段名 asc;
    指定降序:desc
    select username from users order by 字段名 desc;
    双重需求:
    select username from users order by 字段名1 desc,字段名2 asc;
    # 分组函数
    select sum(grade) from users;
    select avg(grade) from users;
    select max(grade) from users;
    select min(grade) from users;
    # 空处理函数
    select sum(ifnull(salary,0)*12), from crew;
    求一年的薪水之和,当薪水为NULL时,被当作0来处理
    # group by 与 having
    group by:按照某个字段或某些字段进行分组
    having:对分组之后的数据进行再次过滤,即having 必须跟在 group by 后面使用
    select max(grade) from students group by classes;
    先根据班级分组,再查出各个班级的成绩最高学生的成绩
    1.分组函数一般与 group by 联合使用,并且任何一个分组函数(count,sum,avg,max,min)都是堆一组数据进行操作的
    2.当一条sql语句没有 group by 时,整张表会自成一组
    3.当sql语句中使用group by时,select之后只能跟参与分组的字段或者分组函数
    # distinct 去重
    distinct 关键字 去除重复记录
    select distinct job from company;
    查询该公司中的工作岗位
    # 语句执行顺序
    select 5号:挑选出满足条件的数据
    from 1号:定表
    where 2号:过滤原始数据
    group by 3号:进行分组
    having 4号:对数据进行再次过滤
    order by 6号:进行排序
    1.字符串数据 sum,avg 为 0,max,min 按字母大小取
    2.分组函数会自动忽略 NULL
    3.数学运算 中如果有NULL参与,结果为定为NULL
    4.分组函数不能直接出现在 where 后面,原因是 group by 是在where语句执行结束之后执行的
    5.分组函数可组合使用
    # inner join
    select a.ename,b.dname from emp a join dept b on a.deptno=b.deptno;
    # left/right join
    select dname,ename from dept a left join emp b on a.deptno=b.deptno;

    or 语句:当前面语句不符合情况或者出现错误时执行or后面的内容

上一篇:SQL 查询的执行顺序


下一篇:sql中的join