系统城装机大师 - 固镇县祥瑞电脑科技销售部宣传站!

当前位置:首页 > 数据库 > MsSql > 详细页面

SQL注入语义分析库libinjection简介

时间:2023-10-26来源:系统城装机大师作者:佚名

SQL注入语义分析库libinjection

什么是libinjection

libinjection是一款用于防御SQL注入攻击的开源软件库。它是由C语言编写的,可以嵌入到任何Web应用程序中,并可以较为准确地检测和防止恶意SQL注入语句。libinjection采用了基于正则表达式的技术来识别和拦截SQL注入攻击,同时其开放源代码的特点也使得其具备了较高的可定制性和扩展性。

libinjection是一个基于C语言的SQLi词法解析分析器,它可以通过对不同语句进行词法分析和语法分析来实现对SQL语句以及HTML语句的解析。

在此之前,市场上绝大多数的WAF都是基于正则匹配(Regex)的,很多的WAF(防火墙)以及NGWAF(下一代防火墙)出于性能方面的考虑,都会选择使用这个库来代替常规的正则表达式。

ModSecurity,它是Apache和nginx的流行WAF。ModSecurity捆绑了libinjection,mod_security从2.7.4版本开始就支持libinjection(dectectSQLi-v2.7.4、detectXSS-v2.8.0)。

libinjection和正则表达式

libinjection和正则表达式都是非常有效的防御SQL注入攻击的技术,但两者之间有一些差异和优劣。

libinjection
libinjection是一个专门用于检测SQL注入攻击的库,其使用了一个基于机器学习的算法来分析请求中的SQL语句。与正则表达式相比,它有以下优点:

  • 更准确:libinjection使用机器学习算法分析SQL语句,因此可以更准确地检测SQL注入攻击,同时减少误报率。
  • 更容易维护:libinjection的规则库相对较小,易于维护。
  • 更快:libinjection的性能要比正则表达式好,响应时间更短。

正则表达式
正则表达式是一种常见的用于检测和防御各种Web应用程序攻击(包括SQL注入攻击)的技术。与libinjection相比,它有以下优点:

更通用:正则表达式不仅可用于检测SQL注入攻击,而且还可用于检测其他类型的Web应用程序攻击。更灵活:正则表达式可以使用各种模式和操作符,从而可以灵活地处理各种复杂情况。更可配置性:正则表达式的规则库可以根据实际情况进行定制和配置。

总体而言,libinjection可能比正则表达式更准确,更容易维护,并具有更快的性能,但正则表达式更通用,更灵活,具有更高的可配置性。因此,为了获得最佳的安全性能,您可能需要考虑同时使用这两种技术。

modsecurity 如何使用libinjection

下面是使用libinjection和ModSecurity进行SQL注入检测和预防的步骤:

安装ModSecurity
安装并配置ModSecurity,使其可以与您的Web服务器一起使用。

安装libinjection
安装libinjection并将其与ModSecurity集成。如果您使用的是Debian或Ubuntu,可以使用以下命令进行安装:

sudo apt-get install libinjection-dev

在ModSecurity中使用libinjection
将ModSecurity配置为使用libinjection来检测SQL注入攻击。以下是一个示例ModSecurity规则,可用于检测SQL注入攻击:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
SecRule ARGS "@detectSQLi" \
    "id:1,\
    phase:2,\
    t:none,\
    t:lowercase,\
    t:replaceComments,\
    t:compressWhitespace,\
    ctl:auditLogParts=+E,\
    ctl:debugLogParts=+E,\
    ctl:requestBodyProcessor=XML,\
    ctl:ruleEngine=on,\
    ctl:auditEngine=on,\
    ctl:ruleRemoveByTag=abcd \
    ctl:ruleRemoveById=1 \
    libinjection_check"
 
SecRule &TX:INJECTION @eq 1 \
    "id:2,\
    phase:2,\
    t:none,\
    ctl:auditLogParts=+E,\
    ctl:debugLogParts=+E,\
    ctl:requestBodyProcessor=XML,\
    ctl:ruleEngine=on,\
    ctl:auditEngine=On,\
    ctl:ruleRemoveByTag=abcd \
    ctl:ruleRemoveById=2 \
    block"

这个规则中包含了两个SecRule。第一个将对输入请求进行规范化和过滤,然后使用libinjection检测SQL注入攻击。第二个SecRule将根据检测结果来做出相应的动作,例如阻止访问请求或将其记录在日志中。

ModSecurity只用了libinjection防御sql注入吗?

ModSecurity不仅使用了libinjection,还使用了正则表达式等多种技术来进行SQL注入攻击防御。实际上,在ModSecurity中使用正则表达式是非常常见的一种方法,因为这种方法可以用于检测和阻止各种类型的Web应用程序攻击,包括SQL注入攻击。

以下是一个示例ModSecurity规则,使用正则表达式检测SQL注入攻击:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
SecRule ARGS "@detectSQLi" \
    "id:1,\
    phase:2,\
    t:none,\
    t:lowercase,\
    t:replaceComments,\
    t:compressWhitespace,\
    ctl:auditLogParts=+E,\
    ctl:debugLogParts=+E,\
    ctl:requestBodyProcessor=XML,\
    ctl:ruleEngine=on,\
    ctl:auditEngine=on,\
    ctl:ruleRemoveByTag=abcd \
    ctl:ruleRemoveById=1 \
    libinjection_check"
 
SecRule &TX:INJECTION @eq 1 \
    "id:2,\
    phase:2,\
    t:none,\
    ctl:auditLogParts=+E,\
    ctl:debugLogParts=+E,\
    ctl:requestBodyProcessor=XML,\
    ctl:ruleEngine=on,\
    ctl:auditEngine=On,\
    ctl:ruleRemoveByTag=abcd \
    ctl:ruleRemoveById=2 \
    block"

虽然语义分析引擎能够更准确地识别和阻止恶意流量,但是正则表达式仍然是一种非常重要的检测方式,可以用来完成一些特定的任务。

例如,对于某些规则化的数据格式,如邮件地址、电话号码和身份证号码等,使用正则表达式可以快速、准确地进行匹配判断。此外,正则表达式还可以用来检测各种类型的注入攻击(如SQL注入和XSS攻击)等漏洞利用行为。

因此,在实际的安全防御中,WAF通常会同时采用多种技术手段,包括语义分析引擎和正则表达式等,以提高其检测能力,并最大程度地保护Web应用程序免受攻击威胁。

WAF研发领域,语义分析相对于正则表达式先进性的研究

多年以来,WAF对攻击的检测,通常使用正则表达式,典型的如ModSecurity。作为老牌的WAF,其拥有庞大的正则规则库。其检测率高,但也正因为规则数量庞大,正则逐一匹配,此过程速度慢,性能低。

对于同步检测的WAF产品,部署并对网站提供防护后,会带来不小的访问性能影响。

新兴的WAF产品,渐有使用语义分析引擎取代正则表达式检测。
其优势究竟何在,性能又能提升多少?

WAF研发领域,语义分析相对于正则表达式先进性的研究
直接查看原文链接: https://www.toutiao.com/article/6944906084217799207/

libinjection架构和使用

官方使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <string.h>
#include "libinjection.h"
 
int main(int argc, const char* argv[])
{
    char fingerprint[8];
    const char* input;
    size_t slen;
    int issqli;
 
    if (argc < 2) {
        fprintf(stderr, "Usage: %s inputstring\n", argv[0]);
        return -1;
    }
 
    input = argv[1];
    slen = strlen(input);
 
 
    issqli = libinjection_sqli(input, slen, fingerprint);
    if (issqli) {
        printf("sqli with fingerprint of '%s'\n", fingerprint);
    } else {
        printf("not sqli\n");
    }
 
 
    return issqli;
}

具体的检查sql注入实现为 libinjection_is_sqli

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
int libinjection_is_sqli(struct libinjection_sqli_state * sql_state)
{
    const char *s = sql_state->s;
    size_t slen = sql_state->slen;
 
    /*
     * no input? not SQLi
     */
    if (slen == 0) {
        return FALSE;
    }
 
    /*
     * test input "as-is"
     */
    libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_NONE | FLAG_SQL_ANSI);
    if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
                          sql_state->fingerprint, strlen(sql_state->fingerprint))) {
        return TRUE;
    } else if (reparse_as_mysql(sql_state)) {
        libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_NONE | FLAG_SQL_MYSQL);
        if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
                              sql_state->fingerprint, strlen(sql_state->fingerprint))) {
            return TRUE;
        }
    }
 
    /*
     * if input has a single_quote, then
     * test as if input was actually '
     * example: if input if "1' = 1", then pretend it's
     *   "'1' = 1"
     * Porting Notes: example the same as doing
     *   is_string_sqli(sql_state, "'" + s, slen+1, NULL, fn, arg)
     *
     */
    if (memchr(s, CHAR_SINGLE, slen)) {
        libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_SINGLE | FLAG_SQL_ANSI);
        if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
                              sql_state->fingerprint, strlen(sql_state->fingerprint))) {
            return TRUE;
        } else if (reparse_as_mysql(sql_state)) {
            libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_SINGLE | FLAG_SQL_MYSQL);
            if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
                                  sql_state->fingerprint, strlen(sql_state->fingerprint))) {
                return TRUE;
            }
        }
    }
 
    /*
     * same as above but with a double-quote "
     */
    if (memchr(s, CHAR_DOUBLE, slen)) {
        libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_DOUBLE | FLAG_SQL_MYSQL);
        if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT,
                              sql_state->fingerprint, strlen(sql_state->fingerprint))) {
            return TRUE;
        }
    }
 
    /*
     * Hurray, input is not SQLi
     */
    return FALSE;
}

这段代码是用于检测 SQL 注入攻击的,通过调用 libinjection 库对输入的 SQL 查询语句进行指纹识别,并判断是否存在于已知的 SQL 注入指纹库中。

  • 首先获取输入字符串 s 和其长度 slen。如果输入字符串长度为0,则直接返回 FALSE,不需要进行检测。
  • 接着,对输入的 SQL 查询语句进行指纹识别,并标记 FLAG_QUOTE_NONE 和 FLAG_SQL_ANSI 标志位。然后通过 sql_state->lookup 函数查找该指纹是否已经存在于数据库中,如果存在则返回 TRUE。

“test input as-is” 的意思是对输入的 SQL 语句进行原样测试,即不进行任何转义或处理。这相当于将输入的 SQL 语句作为一个整体进行指纹识别,并标记 FLAG_QUOTE_NONE 和 FLAG_SQL_ANSI 标志位,在已知的 SQL 注入指纹库中查找是否存在相同的指纹。如果存在,则说明该输入可能是 SQL 注入攻击,否则继续进行其他检测。通常情况下,如果输入字符串包含单引号或双引号字符或者 SQL 关键字,就需要进行进一步的检测和处理。

  • 如果该指纹不存在于数据库中,则尝试将查询语句解析为 MySQL 语法,通过 reparse_as_mysql 函数进行转换。如果转换成功,则再次调用 libinjection_sqli_fingerprint 函数对转换后的 SQL 查询语句进行指纹识别,并标记 FLAG_QUOTE_NONE 和 FLAG_SQL_MYSQL 标志位。最后再次通过 sql_state->lookup 函数查找该指纹是否存在于数据库中,如果存在则返回 TRUE。
  • 接下来,如果输入的字符串中包含单引号字符,则调用 libinjection_sqli_fingerprint 函数对 SQL 查询语句进行指纹识别,并标记 FLAG_QUOTE_SINGLE 和 FLAG_SQL_ANSI 标志位。然后通过 sql_state->lookup 函数查找该指纹是否已经存在于数据库中,如果存在则返回 TRUE。
  • 如果该指纹不存在于数据库中,则尝试将查询语句解析为 MySQL 语法,通过 reparse_as_mysql 函数进行转换。如果转换成功,则再次调用 libinjection_sqli_fingerprint 函数对转换后的 SQL 查询语句进行指纹识别,并标记 FLAG_QUOTE_SINGLE 和 FLAG_SQL_MYSQL 标志位。最后再次通过 sql_state->lookup 函数查找该指纹是否存在于数据库中,如果存在则返回 TRUE。
  • 最后,如果输入的字符串中包含双引号字符,则调用 libinjection_sqli_fingerprint 函数对 SQL 查询语句进行指纹识别,并标记 FLAG_QUOTE_DOUBLE 和 FLAG_SQL_MYSQL 标志位。然后通过 sql_state->lookup 函数查找该指纹是否已经存在于数据库中,如果存在则返回 TRUE。
  • 如果输入字符串没有被识别为 SQL 注入攻击,则最后返回 FALSE。

总结,这段代码是用于检测 SQL 注入攻击,通过指纹识别技术来进行检测和防御。同时支持 ANSI SQL 和 MySQL 两种语法,并能够检测包含单引号和双引号字符以及 SQL 关键字的字符串。

例如,输入常用的SQL注入的检测语句 :’ and 1=1
libinjection会将其转换为s&1,其中单引号依据定义被转换为s,and被转换为&,数字被转换为1。

libinjection在转换完后,通过二分查找算法对内置的特征进行匹配,匹配到则将SQL注入识别特征复制进fingerprint变量并返回。

转换 搜索关键字: sql_keywords ,在文件libinjection_sqli_data.h 中~!

在libinjection中,将SQL关键字转换为单个字母时使用的字符集通常是a-z或A-Z。这意味着只有26个不同的字母可以用来表示所有的SQL关键字。

为了解决这个问题**,libinjection使用了一些技巧来扩展字母表的大小。其中一个技巧是引入数字后缀。例如,对于两个关键字SELECT和SET,它们都会被转换为字母s。为了避免冲突,第二个关键字SET会被转换为字母s2。**

另一个技巧是使用大写字母表示特殊的关键字。例如,LIMIT和OFFSET是MySQL和PostgreSQL中常用的关键字,它们被分别映射为L和O。这样做的好处是,即使一个关键字被映射为小写字母,仍然可以通过使用大写字母来表示其他特殊关键字,以避免冲突。

需要注意的是,虽然仅有26个字母可以用来表示所有的SQL关键字,但由于上面提到的技巧,libinjection能够支持更多的关键字,并确保每个关键字都使用唯一的单个字母来表示。

分享到:

相关信息

  • SQL Server 数据库中的收缩数据库和文件操作

    收缩数据文件通过将数据页从文件末尾移动到更靠近文件开头的未占用的空间来恢复空间,在文件末尾创建足够的空间后,可取消对文件末尾的数据页的分配并将它们返回给文件系统,本文给大家介绍SQL Server 数据库中的收缩数据...

    2023-10-27

  • dbeaver配置SQL server连接实现

    一、需要java jdk环境,我用的比较新 二、dbeaver新建连接SQL server...

    2023-10-27

系统教程栏目

栏目热门教程

人气教程排行

站长推荐

热门系统下载