Java jdbc - 如何执行严格只读的语句

时间:2015-10-19 12:54:24

标签: java sqlite jdbc

我的服务器应用程序几乎在所有情况下都使用预准备语句,以防止sql注入。然而,提供执行原始SELECT查询的特殊用户需要一种可能性。

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

非常感谢!

3 个答案:

答案 0 :(得分:4)

JDBC通过调用Connection.setReadOnly(true)支持只读连接。然而,javadoc说:

  

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

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

否则,你可以做一个简单的"解析SQL语句,以确保它是单个有效SELECT语句。

答案 1 :(得分:2)

我不知道一般指定readonly的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

答案 2 :(得分:2)

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

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());
 }