【问题标题】:Java jdbc - how to execute a statement strictly read onlyJava jdbc - 如何执行严格只读的语句
【发布时间】:2016-01-17 19:59:40
【问题描述】:

我的服务器应用几乎在所有情况下都使用准备好的语句,以防止 sql 注入。尽管如此,仍需要提供执行原始 SELECT 查询的特殊用户的可能性。

如何或多或少安全地确保查询不会修改数据库?是否可以执行只读查询,或者是否有任何其他“安全”方式确保没有人尝试任何 sql 注入? (使用 sqlite3,所以我不能使用任何权限)

非常感谢!

【问题讨论】:

  • 我建议创建一个只有执行选择权限的数据库帐户 ....
  • @StephenC 我也是这么想的。@SalkinD 创建对特定表具有只读权限的用户,并在您的应用程序中使用该用户进行 JDBC 连接
  • @StephenC,sqlite3 不提供任何“数据库帐户”,也没有 GRANT 或 REVOKE 命令。我正在寻找类似 statement.setReadOnly 或类似的东西

标签: java sqlite jdbc


【解决方案1】:

如果您使用某种工厂类来创建或返回到数据库的连接,您可以单独将连接设置为只读:

public Connection getReadOnlyConnection() {
    // Alternatively this could come from a connection pool:
    final Connection conn = DriverManager.getConnection("jdbc:sqlite:sample.db");
    conn.setReadOnly(true);
    return conn;
}

如果您使用的是连接池,那么您可能还想提供一种获取可写连接的方法:

public Connection getWriteableConnection() {
     final Connection conn = getPooledConnection(); // I'm assuming this method exists!
     conn.setReadOnly(false);
     return conn;
}

您也可以只提供一个getConnection(boolean readOnly) 方法,然后简单地将参数传递给setReadOnly(boolean) 调用。我个人更喜欢单独的方法,因为它使您的意图更加清晰。

另外,某些数据库(如 Oracle)提供可以启用的只读模式。 SQLite 没有提供,但您可以通过简单地将实际的数据库文件(包括目录)设置为只读文件系统本身来模拟它。

另一种方法如下(归功于deadlock for the below code):

public Connection getReadOnlyConnection() {
    SQLiteConfig config = new SQLiteConfig();
    config.setReadOnly(true);
    Connection conn = DriverManager.getConnection("jdbc:sqlite:sample.db",
            config.toProperties());
 }

【讨论】:

    【解决方案2】:

    JDBC 通过调用Connection.setReadOnly(true) 来支持只读连接。但是 javadoc 说:

    将此连接置于只读模式,作为提示驱动程序以启用数据库优化

    一些 JDBC 驱动程序将强制执行只读请求,其他人将仅将其用于优化,或者干脆忽略它。我不知道sqlite3 是如何实现的。您必须对此进行测试。

    否则,您可以对 SQL 语句进行“简单”解析,以确保它是单个有效的SELECT 语句。

    【讨论】:

      【解决方案3】:

      我不知道指定只读的一般 JBDC 配置。但是 Sqlite 确实有特殊的数据库打开模式,可以在连接到 sqlite 数据库时利用它。例如。

      Properties config = new Properties();
      config.setProperty("open_mode", "1");  //1 == readonly
      Connection conn = DriverManager.getConnection("jdbc:sqlite:sample.db", config);
      

      信用:https://stackoverflow.com/a/18092761/62344

      FWIW 所有支持的打开模式都可以看到here

      【讨论】:

      • 谢谢,尽管如此。尽管如此,在这种情况下,我必须为此关闭我的活动连接,并在此操作后再次重新打开它。我正在寻找不需要关闭/打开/关闭/打开的解决方案
      • 读/写访问是在驱动程序级别,而不是应用程序级别。一个技巧是维护一个连接池,并根据需要重新打开。它比一个连接来统治它们更复杂,特别是对于单客户端样式的应用程序,但这意味着您可以为手头的应用程序指定连接。它还可以使应用程序对某些类型的数据库异常更具弹性。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-31
      • 2013-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多