Java 枚举值和 SQL 注入

Java enum values and SQL injection

我有以下枚举:

public enum AccountStatus {

    ENABLED,
    CONFIRMATION_PENDING,
    EXPIRED,
    LOCKED,
    DISABLED,
    CREDENTIALS_EXPIRED,
}

我以 JSP 形式绑定到复选框:

<li><form:checkbox path="accountStatus" value="ENABLED" label="Enabled" /></li>
<li><form:checkbox path="accountStatus" value="CONFIRMATION_PENDING" label="Confirmation Pending" /></li>
...
<li><form:checkbox path="accountStatus" value="CREDENTIALS_EXPIRED" label="Credentials Expired" /></li>

在我的控制器中,当我获得选中的复选框值时,我将字符串转换为枚举,如下所示:

AccountStatus accountStatus = AccountStatus.valueOf("selected string here");

然后在我的 DAO 中(使用 Spring JdbcTemplate)我使用选定的值查询我的数据库:

String SQL = "SELECT * FROM TABLE_A WHERE column = \'" + accountStatus.name() + "\'";

jdbcTemplate.query(SQL, new MyMapper());

由于我正在使用 AccountStatus.valueOf(...) 验证每个用户选中的复选框,这种方法是否可以避免 SQL 注入?

您也可以使用http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/EnumUtils.html

这个库包含很多有用的工具类

TypeEnum strTypeEnum = null;

// check if string makes valid enum
if( EnumUtils.isValidEnum(TypeEnum.class, str) ){
    strTypeEnum = TypeEnum.valueOf(str);
}

您不会因为您显示此枚举值设置的方式而任意注入 SQL 的危险。攻击者可以发送无效的枚举名称,但 valueOf 会在无法将其与有效值匹配时抛出 IllegalArgumentException。

如果出于某种原因不应输入有效的枚举值(例如,特定角色无权查找具有 DISABLED 值的条目),则在没有其他服务器端验证的情况下攻击者可以将条目更改为该有效但不允许的值。所以这可能是一次攻击,您可以通过添加更多验证来补救(在我的示例中,检查用户角色是否允许枚举值)。

重写它以使用参数(最好是 named parameters)会提高此 SQL 的易读性。此外,这将不断出现在每次代码审查、静态代码分析和代码审计中,我会很生气不得不继续回答有关它的问题。但我理解想要避免接触正在工作的复杂事物。