Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

selectLimit 只在第一条sql 生效 #2649

Closed
marvin9551 opened this issue Jun 19, 2018 · 8 comments
Closed

selectLimit 只在第一条sql 生效 #2649

marvin9551 opened this issue Jun 19, 2018 · 8 comments
Assignees
Milestone

Comments

@marvin9551
Copy link

druid版本 druid-spring-boot-starter 1.1.4 设置select-limit:5 只有在第一条语句的时候
SELECT id, serviceTypeId, name, description, price
, isDeleted, isRadioOption, serviceSubTypeId, imageUrl, serviceCategoryId
, isPublicVisit, finance_category, star_level, work_type_id, fast_repair
, charge_model_same, maintenance_period, maintenance_miles
FROM ServiceSubItem
WHERE isDeleted = 0
AND serviceTypeId = ?
AND serviceCategoryId = ?
LIMIT 5

第二次就不再limit了
SELECT id, serviceTypeId, name, description, price
, isDeleted, isRadioOption, serviceSubTypeId, imageUrl, serviceCategoryId
, isPublicVisit, finance_category, star_level, work_type_id, fast_repair
, charge_model_same, maintenance_period, maintenance_miles
FROM ServiceSubItem
WHERE isDeleted = 0
AND serviceTypeId = ?
AND serviceCategoryId = ?

@wenshao
Copy link
Member

wenshao commented Jun 19, 2018

你调用的什么API?

@marvin9551
Copy link
Author

配置druid的wallfilter设置selectLimit,没有调用什么api

@qixiaobo
Copy link

qixiaobo commented Aug 15, 2018

我也看到了 目前看起来似乎是使用了druid的statement缓存 而大部分wallfilter的check是执行check方法或者说checkInternal

private WallCheckResult checkInternal(String sql) throws SQLException {
        WallCheckResult checkResult = provider.check(sql);
        List<Violation> violations = checkResult.getViolations();

        if (violations.size() > 0) {
            Violation firstViolation = violations.get(0);
            if (isLogViolation()) {
                LOG.error("sql injection violation, " + firstViolation.getMessage() + " : " + sql);
            }

            if (throwException) {
                if (violations.get(0) instanceof SyntaxErrorViolation) {
                    SyntaxErrorViolation violation = (SyntaxErrorViolation) violations.get(0);
                    throw new SQLException("sql injection violation, " + firstViolation.getMessage() + " : " + sql,
                            violation.getException());
                } else {
                    throw new SQLException("sql injection violation, " + firstViolation.getMessage() + " : " + sql);
                }
            }
        }

        return checkResult;
    }

而关于check方法封装

  public String check(String sql) throws SQLException {
        return checkInternal(sql)
                .getSql();
    }

但是大部分使用的都是预编译 即preparedStatement
但是如下方法

    @Override
    public boolean preparedStatement_execute(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
        try {
            wallUpdateCheck(statement);

            boolean firstResult = chain.preparedStatement_execute(statement);

            if (!firstResult) {
                WallSqlStat sqlStat = (WallSqlStat) statement.getAttribute(ATTR_SQL_STAT);
                int updateCount = statement.getUpdateCount();
                if (sqlStat != null) {
                    provider.addUpdateCount(sqlStat, updateCount);
                }
            }

            return firstResult;
        } catch (SQLException ex) {
            incrementExecuteErrorCount(statement);
            throw ex;
        }
    }

并未调用check方法

@qixiaobo
Copy link

目前可以看到有更多信息 如果开启了poolPreparedStatements的时候 由于PreparedStatements会被池化缓存 这样将不会触发check 在没有对于PreparedStatement进行check之前 我只能先关闭pool了

spring.datasource.poolPreparedStatements=false
#spring.datasource.maxPoolPreparedStatementPerConnectionSize=20

@wenshao
Copy link
Member

wenshao commented Aug 15, 2018

1.1.10试试看?

@qixiaobo
Copy link

试过了~从1.1.4 测试到了1.1.10 ~ 确实是有问题的
当pool开启的时候wall会失效【主要指预编译】
version: 1.1.10
config:

#由于wallfilter当缓存时无法触发 https://github.com/alibaba/druid/issues/2649
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.useGlobalDataSourceStat=true
# 配置StatFilter
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=1000
# 配置WallFilter
spring.datasource.druid.filter.wall.enabled=true
spring.datasource.druid.filter.wall.db-type=mysql
spring.datasource.druid.filter.wall.config.delete-allow=false
spring.datasource.druid.filter.wall.config.drop-table-allow=false
#是否允许非以上基本语句的其他语句,缺省关闭,通过这个选项就能够屏蔽DDL。
spring.datasource.druid.filter.wall.config.none-base-statement-allow=false
#检查UPDATE语句是否无where条件,这是有风险的,但不是SQL注入类型的风险
spring.datasource.druid.filter.wall.config.update-where-none-check=false
#SELECT ... INTO OUTFILE 是否允许,这个是mysql注入攻击的常见手段,缺省是禁止的
spring.datasource.druid.filter.wall.config.select-into-outfile-allow=false
#是否允许调用Connection.getMetadata方法,这个方法调用会暴露数据库的表信息
spring.datasource.druid.filter.wall.config.metadata-allow=true
#对被认为是攻击的SQL进行LOG.error输出
spring.datasource.druid.filter.wall.log-violation=true
#对被认为是攻击的SQL抛出SQLExcepton 系统稳定之后可以放开
spring.datasource.druid.filter.wall.throw-exception=false
#开启slf4j日志
spring.datasource.druid.filter.slf4j.enabled=true
spring.datasource.druid.filter.slf4j.statement-executable-sql-log-enable=true
spring.datasource.druid.filter.slf4j.statement-log-enabled=true
spring.datasource.druid.filter.slf4j.statement-log-error-enabled=true
spring.datasource.druid.filter.slf4j.result-set-log-enabled=true
spring.datasource.druid.filter.slf4j.result-set-log-error-enabled=true

@starlight36
Copy link

starlight36 commented Nov 6, 2019

遇到了相同的问题,研究了一下,发现在wallprovider里面使用了LRUCache来缓存黑白名单,存入cache的是rewrite之前的SQL,后续从cache里面读取时使用了未被rewrite的SQL。

WallProvider.java#L598

// first step, check whiteList
boolean mulltiTenant = config.getTenantTablePattern() != null && config.getTenantTablePattern().length() > 0;
if (!mulltiTenant) {
    WallCheckResult checkResult = checkWhiteAndBlackList(sql);
    if (checkResult != null) {
        checkResult.setSql(sql);
        return checkResult;
    }
}

此处如果能读到缓存,就直接返回缓存内的SQL解析结果,使用了原始SQL。

WallProvider.java#L705

if ((!updateCheckHandlerEnable) && sql.length() < MAX_SQL_LENGTH) {
    sqlStat = addWhiteSql(sql, tableStat, context.getFunctionStats(), syntaxError);
}

而写入时使用的是Rewrite之前的SQL语句,直接无视了Rewrite后的SQL

@wenshao wenshao self-assigned this Nov 25, 2019
@wenshao wenshao added the Bug label Nov 25, 2019
@wenshao wenshao added this to the 1.1.22 milestone Nov 25, 2019
@wenshao wenshao modified the milestones: 1.1.22, 1.1.23 Jun 27, 2020
@wenshao wenshao modified the milestones: 1.1.23, 1.2.2 Oct 7, 2020
@wenshao wenshao modified the milestones: 1.2.2, 1.2.3, 1.2.4 Nov 3, 2020
@wenshao wenshao modified the milestones: 1.2.4, 1.2.5 Dec 12, 2020
@wenshao
Copy link
Member

wenshao commented Feb 17, 2021

https://github.com/alibaba/druid/releases/tag/1.2.5
问题已修复,请用新版本

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants