HOOOS

Druid连接池SQL防火墙:原理、配置与SQL注入防御实战

0 80 小D DruidSQL注入数据库安全
Apple

大家好,我是你们的数据库安全小助手“小D”。今天咱们来聊聊Druid连接池的SQL防火墙功能,这可是保护数据库安全的一道重要防线。很多小伙伴可能听说过SQL注入攻击,这是一种非常危险的攻击方式,而Druid的SQL防火墙就能有效拦截这类攻击。接下来,我会详细介绍SQL防火墙的原理、配置方法,并通过实际案例演示如何拦截SQL注入攻击,以及如何处理误拦截的情况。

1. 为什么要用SQL防火墙?

在聊Druid的SQL防火墙之前,咱们先来了解一下为什么需要SQL防火墙。想象一下,如果你的数据库没有安全防护,就像家门没锁一样,坏人可以随意进出,窃取数据,甚至破坏你的系统。SQL注入攻击就是这样一种“坏人”,它利用应用程序的漏洞,向数据库发送恶意的SQL语句,从而达到非法目的。

举个例子,假设你的网站有一个登录功能,用户需要输入用户名和密码。正常的SQL查询语句可能是这样的:

SELECT * FROM users WHERE username = '输入的用户名' AND password = '输入的密码';

但如果攻击者在用户名或密码框中输入一些特殊的字符,比如 ' OR '1'='1,SQL语句就变成了:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '' OR '1'='1';

由于 '1'='1' 永远为真,这条SQL语句就会返回所有用户信息,攻击者就成功绕过了登录验证,获取了所有用户的账号密码!

这就是SQL注入攻击的威力。为了防止这种攻击,我们需要一个“门卫”,在SQL语句到达数据库之前进行检查,拦截掉那些恶意的SQL语句,这就是SQL防火墙的作用。

2. Druid SQL防火墙的原理

Druid连接池内置了一个强大的SQL防火墙,它基于SQL语法分析来实现安全防护。Druid的防火墙并不是简单地通过字符串匹配来判断SQL语句是否合法,而是会先对SQL语句进行语法解析,将其转换成一个抽象语法树(AST)。

AST是一种树状结构,它将SQL语句的各个组成部分(如SELECT、FROM、WHERE等)表示为树的节点。通过分析AST,Druid防火墙可以准确地识别出SQL语句的意图,判断它是否包含潜在的风险。

Druid防火墙的核心组件是WallFilter,它实现了Druid的Filter接口。WallFilter内部使用WallProvider来提供具体的防火墙规则和配置。WallProvider会根据预定义的规则,对AST进行检查,如果发现违反规则的SQL语句,就会阻止其执行,并抛出SQLException

Druid的防火墙规则非常灵活,可以根据需要进行配置。例如,你可以配置允许或禁止执行的SQL语句类型(如SELECT、UPDATE、DELETE等),可以限制访问的表和列,还可以自定义一些安全规则。

3. 如何配置Druid SQL防火墙

配置Druid SQL防火墙非常简单,主要有两种方式:

3.1. 通过DruidDataSource的配置属性

你可以在创建DruidDataSource时,通过设置filters属性来启用WallFilter,并通过wall.*开头的属性来配置防火墙规则。例如:

DruidDataSource dataSource = new DruidDataSource();
dataSource.setFilters("wall");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("password");

// 配置防火墙规则
dataSource.setConnectionProperties("druid.wall.allowMultiStatement=false;druid.wall.dropTableAllow=false");

在上面的例子中,我们启用了WallFilter,并通过connectionProperties设置了两个防火墙规则:

  • druid.wall.allowMultiStatement=false:禁止执行多条SQL语句(防止攻击者通过分号分隔符执行多条恶意语句)。
  • druid.wall.dropTableAllow=false:禁止执行DROP TABLE语句(防止攻击者删除数据库表)。

3.2. 通过Spring Boot配置

如果你使用Spring Boot,可以通过application.propertiesapplication.yml文件来配置Druid SQL防火墙。例如:

# 启用WallFilter
spring.datasource.druid.filters=wall

# 配置防火墙规则
spring.datasource.druid.wall.config.allow-multi-statement=false
spring.datasource.druid.wall.config.drop-table-allow=false

与直接配置DruidDataSource类似,这里我们同样禁用了多语句执行和DROP TABLE语句。

3.3. 常用的防火墙配置选项

Druid提供了丰富的防火墙配置选项,可以满足各种安全需求。以下是一些常用的配置选项:

配置项 说明 默认值
druid.wall.allowMultiStatement 是否允许执行多条SQL语句 false
druid.wall.dropTableAllow 是否允许执行DROP TABLE语句 false
druid.wall.deleteAllow 是否允许执行DELETE语句 true
druid.wall.updateAllow 是否允许执行UPDATE语句 true
druid.wall.insertAllow 是否允许执行INSERT语句 true
druid.wall.selectAllow 是否允许执行SELECT语句 true
druid.wall.readOnly 是否将数据库连接设置为只读模式(只允许SELECT语句) false
druid.wall.checkInterval 防火墙规则检查间隔(毫秒) 3000
druid.wall.logViolation 是否记录违反防火墙规则的SQL语句 false
druid.wall.throwViolation 是否在发现违反防火墙规则的SQL语句时抛出异常 true
druid.wall.violationLogName 记录违反防火墙规则的SQL语句的日志名称 druid.wall
druid.wall.config.selelctIntoOutfileAllow 是否允许使用select ... into outfile false
druid.wall.config.selectWhereNoneCheck 对查询语句 where 条件中 永假 的情况是否允许。永假示例:1 = 2。 true

你可以根据自己的安全需求,灵活组合这些配置选项。建议根据最小权限原则,只允许必要的SQL操作,禁止不必要的操作,以最大程度地降低安全风险。

4. SQL注入防御实战

现在,我们通过几个实际案例来演示Druid SQL防火墙如何拦截SQL注入攻击。

4.1. 案例1:绕过登录验证

我们回到前面提到的登录验证的例子。假设攻击者在用户名框中输入 ' OR '1'='1,如果没有防火墙,SQL语句就会变成:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '...';

这条语句会返回所有用户信息,攻击者就可以绕过登录验证。

现在,我们启用Druid SQL防火墙,并设置 druid.wall.selectWhereNoneCheck=true,也就是对永假条件进行拦截。 这时,Druid防火墙会检测到'1'='1'这个永真条件,判断为潜在的SQL注入攻击,并阻止这条SQL语句的执行,抛出SQLException

4.2. 案例2:批量删除数据

假设攻击者想通过SQL注入来删除数据库中的数据。他可能会构造类似以下的SQL语句:

DELETE FROM users WHERE id > 0;

这条语句会删除users表中的所有数据。

如果我们启用了Druid SQL防火墙,并设置druid.wall.deleteAllow=false,那么这条SQL语句就会被拦截,因为防火墙禁止了DELETE操作。

4.3. 案例3:读取敏感数据

假设数据库中有一张credit_cards表,存储了用户的信用卡信息。攻击者可能会尝试通过SQL注入来读取这些敏感数据:

SELECT card_number, cvv, expiry_date FROM credit_cards;

为了防止这种攻击,我们可以配置Druid SQL防火墙,禁止访问credit_cards表。具体做法是,可以在WallConfig中设置blackList,将credit_cards表加入黑名单。这样,任何试图访问credit_cards表的SQL语句都会被拦截。

5. 如何处理误拦截

虽然Druid SQL防火墙非常智能,但有时也可能会出现误拦截的情况。比如,你的应用程序中可能有一些正常的SQL语句,但由于某些原因被防火墙误判为攻击。这时,你就需要对防火墙规则进行调整,或者对SQL语句进行修改。

5.1. 调整防火墙规则

如果你的SQL语句是合法的,但被防火墙误拦截,你可以考虑调整防火墙规则。比如,如果你的应用程序需要执行多条SQL语句,你可以将druid.wall.allowMultiStatement设置为true。如果你的应用程序需要执行DROP TABLE语句(当然,这通常不推荐),你可以将druid.wall.dropTableAllow设置为true

5.2. 修改SQL语句

如果你的SQL语句本身存在问题,或者触发了防火墙的某些规则,你可以考虑修改SQL语句。比如,如果你的SQL语句中包含了一些特殊的字符,可能会被防火墙误判为注入攻击,你可以尝试对这些字符进行转义,或者使用参数化查询。

5.3. 使用白名单

如果你的应用程序中有一些固定的、安全的SQL语句,你可以将它们加入Druid防火墙的白名单。这样,这些SQL语句就不会被防火墙拦截。具体做法是,可以在WallConfig中设置whiteList,将这些SQL语句加入白名单。

###5.4 关闭特定规则
Druid 提供了很多细粒度的规则,可以单独关闭某一个规则,以 WallConfig 为例,如果想停用 selectLimitCheck,可以这么配置:

wallConfig.setSelectLimitCheck(false);

6. 总结

Druid SQL防火墙是保护数据库安全的重要工具,它可以有效拦截SQL注入攻击,防止数据泄露和破坏。通过合理的配置,你可以根据自己的安全需求,定制防火墙规则,最大程度地降低安全风险。记住,最小权限原则是配置防火墙的关键,只允许必要的SQL操作,禁止不必要的操作。希望今天的分享对你有帮助,如果你有任何问题,欢迎随时向我提问。下次再见!

7. 附录:Druid 防火墙的配置项(WallConfig)

配置项 说明 默认值
dir 信任的配置文件的目录
configFile 防火墙的配置文件的路径
noneBaseStatementAllow 是否允许非基本的语句(除了SELECT、INSERT、UPDATE、DELETE之外的语句) false
selectIntoOutfileAllow 是否允许SELECT ... INTO OUTFILE语句 false
selectUnionCheck 是否检查SELECT语句中的UNION操作 true
selectWhereAlwayTrueCheck 是否检查SELECT语句的WHERE条件是否永真 true
selectHavingAlwayTrueCheck 是否检查SELECT语句的HAVING条件是否永真 true
selectWhereNoneCheck 是否检查SELECT语句的WHERE条件是否永假 true
deleteWhereNoneCheck 是否检查DELETE语句的WHERE条件是否永假 true
updateWhereNoneCheck 是否检查UPDATE语句的WHERE条件是否永假 true
conditionAndAlwayTrueCheck 是否检查条件表达式中的AND连接的永真条件 true
conditionAndAlwayFalseCheck 是否检查条件表达式中的AND连接的永假条件 true
conditionDoubleConstCompareCheck 是否检查条件表达式中两个常量之间的比较 true
conditionLikeTrueCheck 是否检查条件表达式中的LIKE '%%'或LIKE '%' true
conditionLikeFalseCheck 是否检查条件表达式中的LIKE '' true
conditionLikeReverseCheck 是否检查条件表达式中的'abc' LIKE col true
completeInsertCheck 是否检查INSERT语句是否包含所有列 false
strictSyntaxCheck 是否启用严格的SQL语法检查 true
allowConment 是否允许SQL语句中包含注释 true
allowVariant 是否允许SQL语句中包含变量 true
checkName 是否检查表名和列名的合法性 true
functionCheck 是否检查函数的合法性 true
objectCheck 是否检查对象(如表、视图、函数等)的合法性 true
schemaCheck 是否检查模式(Schema)的合法性 true
tableCheck 是否检查表的合法性 true
mustParameterized 是否要求SQL语句必须参数化 false
allowAlterTable 是否允许执行ALTER TABLE语句 false
allowDropTable 是否允许执行DROP TABLE语句 false
allowRenameTable 是否允许执行RENAME TABLE语句 false
allowCreateView 是否允许执行CREATE VIEW语句 true
allowDropView 是否允许执行DROP VIEW语句 true
allowDropIndex 是否允许执行DROP INDEX语句 true
allowCreateIndex 是否允许执行CREATE INDEX语句 true
allowCreateFunction 是否允许执行CREATE FUNCTION语句 false
allowDropFunction 是否允许执行DROP FUNCTION语句 false
allowCreateProcedure 是否允许执行CREATE PROCEDURE语句 false
allowDropProcedure 是否允许执行DROP PROCEDURE语句 false
allowCreateTrigger 是否允许执行CREATE TRIGGER语句 false
allowDropTrigger 是否允许执行DROP TRIGGER语句 false
allowCreateTable 是否允许执行CREATE TABLE语句 true
allowTruncate 是否允许执行TRUNCATE TABLE语句 false
allowHint 是否允许SQL语句中包含Hint true
allowDescribe 是否允许执行DESCRIBE/DESC语句 true
allowShow 是否允许执行SHOW语句 true
allowReplace 是否允许执行REPLACE语句 true
allowMerge 是否允许执行MERGE语句 true
allowCall 是否允许执行CALL语句 true
limit 查询语句结果集上限 -1
selectLimitCheck 是否对查询语句进行limit 检查 true

点评评价

captcha
健康