【问题标题】:Using prepared statement in the most secure way以最安全的方式使用准备好的语句
【发布时间】:2012-11-05 08:26:08
【问题描述】:

从安全验证的角度来看,两者之间是否有区别:

stmt.setObject(1, theObject);

stmt.setString(1, theObject);?

我知道在这种情况下theObjectString,但我有兴趣使部分代码更通用以涵盖其他情况,并且想知道输入验证的安全性是否受到影响

【问题讨论】:

    标签: java sql validation jdbc prepared-statement


    【解决方案1】:

    可以使用 ssetObject(),因为 jdbc 会尝试对所有 java.lang.* 类型进行类型解析。

    但是,以这种方式将任意 SQL 字符串传递给数据库存在潜在问题 - 安全漏洞:如果没有对用于构建 SQL 字符串的任何参数进行非常明智的验证,您容易受到各种类型的 SQL 插入攻击。

    谨防将无类型的null 传递给setObject()

    【讨论】:

    • 对于setString,SQL 字符串的传递是否也是一个问题?
    • 是的。在执行语句之前,您需要进行一些沙箱检查。
    • 这听起来不正确。我读过建议使用PreparedStatements 进行正确输入。你是说负责“解析”sql事先字符串?
    • 我的意思是您有时需要检查您用作准备好的语句的参数的参数是否不包含“恶意代码 AKA SQL 注入”
    • 所以为了避免 SQL 注入,我应该在上面使用其他东西?
    【解决方案2】:

    恕我直言

    鉴于 JDBC 是一个非常轻量级的数据库服务器包装器(除了生成 SQL 以供数据库直接解释之外,它几乎没有其他作用),我希望

    stmt.setObject(1, theObject);
    

    完全一样

    stmt.setString(1, theObject == null ? "null" : theObject.toString())`;
    

    “类型验证”将在数据库处理生成的 SQL 并查找它是否适合它时发生。

    【讨论】:

    • JDBC 和 ODBC 是两种不同的技术,JDBC 不是 ODBC 的一种包装(尽管存在桥梁)。
    • @Paolo 我知道,我当时缺乏表达。我把它改成了database engine,这样更合适。
    • 但如果这就是输入验证的全部执行方式?未正确转义字符串等?
    • 在该步骤之后强制执行。
    【解决方案3】:

    答案似乎与提供程序相关,并且取决于驱动程序的实现。我检查了当前 postgresql 驱动程序的来源,这两个调用是相等的。

    如果驱动程序不知道类型,则会引发异常。

    /** code from ./org/postgresql/jdbc2/AbstractJdbc2Statement.java */
    public void setObject(int parameterIndex, Object x) throws SQLException
    {
        checkClosed();
        if (x == null)
            setNull(parameterIndex, Types.OTHER);
        else if (x instanceof String)
            setString(parameterIndex, (String)x);
        else if (x instanceof BigDecimal)
            setBigDecimal(parameterIndex, (BigDecimal)x);
        else if (x instanceof Short)
            setShort(parameterIndex, ((Short)x).shortValue());
        else if (x instanceof Integer)
            setInt(parameterIndex, ((Integer)x).intValue());
        else if (x instanceof Long)
            setLong(parameterIndex, ((Long)x).longValue());
        else if (x instanceof Float)
            setFloat(parameterIndex, ((Float)x).floatValue());
        else if (x instanceof Double)
            setDouble(parameterIndex, ((Double)x).doubleValue());
        else if (x instanceof byte[])
            setBytes(parameterIndex, (byte[])x);
        else if (x instanceof java.sql.Date)
            setDate(parameterIndex, (java.sql.Date)x);
        else if (x instanceof Time)
            setTime(parameterIndex, (Time)x);
        else if (x instanceof Timestamp)
            setTimestamp(parameterIndex, (Timestamp)x);
        else if (x instanceof Boolean)
            setBoolean(parameterIndex, ((Boolean)x).booleanValue());
        else if (x instanceof Byte)
            setByte(parameterIndex, ((Byte)x).byteValue());
        else if (x instanceof Blob)
            setBlob(parameterIndex, (Blob)x);
        else if (x instanceof Clob)
            setClob(parameterIndex, (Clob)x);
        else if (x instanceof Array)
            setArray(parameterIndex, (Array)x);
        else if (x instanceof PGobject)
            setPGobject(parameterIndex, (PGobject)x);
        else if (x instanceof Character)
            setString(parameterIndex, ((Character)x).toString());
        else if (x instanceof Map)
            setMap(parameterIndex, (Map)x);
        else
        {
            // Can't infer a type.
            throw new PSQLException(GT.tr("Can''t infer the SQL type to use for an instance of {0}. Use setObject() with an explicit Types value to specify the type to use.", x.getClass().getName()), PSQLState.INVALID_PARAMETER_TYPE);
        }
    }
    

    【讨论】:

    • 如果这样做,输入验证是如何执行的?
    • @Jim 您还想要什么其他类型的验证?例如 sql 注入只能使用字符串,但前提是它不是正确的“转义”。我希望这项工作能正确地完成 jdbc 提供程序:-D。在其他类型上,演员会崩溃。
    • 检查@aviad 的答案。似乎另有暗示
    • @Jim 每次阅读有关 SQL 注入的信息时,专家都建议使用准备好的语句。 IMO 的原因是对准备好的参数进行了更深入的处理——它们仅被设置为数据库的值。没有编译器或其他东西运行来解释它们。但这是一个有趣的问题。下一次我将更深入地研究 JDBC 源代码。顺便说一句,就像源代码一样,对于 postgres jdbc 驱动程序来说,无类型的 null 是没有问题的。
    • @Jim 几年前,我参加了一场关于大学实现数据库系统的讲座。我们了解到,正常的 sql 语句在数据库中按以下步骤处理: 1. 语法检查 2. 优化器 3. 编译器准备执行语句有机会被编译或解释——除了你可以使用缓冲区溢出和其他东西。所以如果今天的数据库都以同样的方式工作,是否应该没有办法通过这种方式进行 sql 注入。
    猜你喜欢
    • 1970-01-01
    • 2010-11-21
    • 2012-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-13
    • 2023-03-07
    相关资源
    最近更新 更多