将字符串文字放入 executeQuery 是否容易在 JDBC 中进行 SQL 注入?
Is putting a string literal in executeQuery prone to an SQL injection in JDBC?
我环顾四周,似乎找不到可靠的答案。我想知道将字符串文字放入 executeQuery()
是否仍然容易受到 SQL 注入。
所以假设我有这个代码:
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/","root","password");
Statement stmt = conn.createStatement();
ResultSet res = stmt.executeQuery("SELECT * from users where uid = "+uid);
这容易发生 SQL 注射吗?
另一个问题是,是否只是让使用这段代码的方法只抛出一个 SQLException,然后在 main 中尝试和捕获可接受的?
例如:
public void execMethod(String uid) throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/","root","password");
Statement stmt = conn.createStatement();
ResultSet res = stmt.executeQuery("SELECT * from users where uid = "+uid);
// execute some other code
res.close();
}
public static void main(String[] args) {
try {
execMethod("123");
execMethod("456");
} catch(Exception ex) {
ex.printStackTrace();
}
}
这是使用 SQL 异常的标准或正确方法吗?我从未真正使用过 SQL,尤其是 Java 和 SQL。我读过的教程似乎只是一种方式,所以我对自己很不确定。
简答:是。
您似乎没有进行任何类型的输入验证,因此没有任何东西可以阻止 uid
成为“105 或 1=1”之类的东西
你应该使用 PreparedStatement
s tutorial here
PreparedStatement stmt = conn.prepareStatement("SELECT * from users where uid = ?")
stmt.setString(1, uid);
..same as before
此外,您不要关闭应该在 finally 块中完成的语句或连接,以防抛出异常
Is this prone to a SQL injection?"
是的,您无法控制 uid
实际包含的内容。
有关详细信息,请参阅 Using Prepared Statements
Another question is, is just making the method that uses this code only throw an SQLException, and then trying and catching in main acceptable?"
是的,但是您至少应该将 execMethod
的内容包含在 try-finally
中,以确保您正在关闭您打开的资源(或者使用 try-with-resources
来表示 Java 7)
public void execMethod(String uid) throws SQLException {
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/", "root", "password")) {
try (PreparedStatement stmt = conn.prepareStatement("SELECT * from users where uid = ?")) {
stmt.setString(1, uid);
try (ResultSet res = stmt.executeQuery()) {
// Process ressult set
}
}
}
}
有关详细信息,请参阅 The try-with-resources Statement
但是,我只会捕获每个调用的 SQLException
,而不是将它们放在一起,因为您不知道什么失败什么成功
try {
execMethod("123");
try {
execMethod("456");
} catch (Exception ex) {
// Maybe undo 123
System.out.println("Failed 456");
ex.printStackTrace();
}
} catch (Exception ex) {
System.out.println("Failed 123");
ex.printStackTrace();
}
(假设456依赖于123的成功)
是的。如果 uid
可以由用户输入(它不是 String
文字)。我建议你使用 PreparedStatement
, and a try-with-resources
like
final String sql = "SELECT * from users where uid = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, uid);
try (ResultSet res = ps.executeQuery()) {
while (res.next()) {
// ...
}
}
}
PreparedStatement
(带绑定变量)至少有这些优点
- 可以使用服务器上的
Statement
缓存
- 不容易SQL注射
我环顾四周,似乎找不到可靠的答案。我想知道将字符串文字放入 executeQuery()
是否仍然容易受到 SQL 注入。
所以假设我有这个代码:
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/","root","password");
Statement stmt = conn.createStatement();
ResultSet res = stmt.executeQuery("SELECT * from users where uid = "+uid);
这容易发生 SQL 注射吗?
另一个问题是,是否只是让使用这段代码的方法只抛出一个 SQLException,然后在 main 中尝试和捕获可接受的?
例如:
public void execMethod(String uid) throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/","root","password");
Statement stmt = conn.createStatement();
ResultSet res = stmt.executeQuery("SELECT * from users where uid = "+uid);
// execute some other code
res.close();
}
public static void main(String[] args) {
try {
execMethod("123");
execMethod("456");
} catch(Exception ex) {
ex.printStackTrace();
}
}
这是使用 SQL 异常的标准或正确方法吗?我从未真正使用过 SQL,尤其是 Java 和 SQL。我读过的教程似乎只是一种方式,所以我对自己很不确定。
简答:是。
您似乎没有进行任何类型的输入验证,因此没有任何东西可以阻止 uid
成为“105 或 1=1”之类的东西
你应该使用 PreparedStatement
s tutorial here
PreparedStatement stmt = conn.prepareStatement("SELECT * from users where uid = ?")
stmt.setString(1, uid);
..same as before
此外,您不要关闭应该在 finally 块中完成的语句或连接,以防抛出异常
Is this prone to a SQL injection?"
是的,您无法控制 uid
实际包含的内容。
有关详细信息,请参阅 Using Prepared Statements
Another question is, is just making the method that uses this code only throw an SQLException, and then trying and catching in main acceptable?"
是的,但是您至少应该将 execMethod
的内容包含在 try-finally
中,以确保您正在关闭您打开的资源(或者使用 try-with-resources
来表示 Java 7)
public void execMethod(String uid) throws SQLException {
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/", "root", "password")) {
try (PreparedStatement stmt = conn.prepareStatement("SELECT * from users where uid = ?")) {
stmt.setString(1, uid);
try (ResultSet res = stmt.executeQuery()) {
// Process ressult set
}
}
}
}
有关详细信息,请参阅 The try-with-resources Statement
但是,我只会捕获每个调用的 SQLException
,而不是将它们放在一起,因为您不知道什么失败什么成功
try {
execMethod("123");
try {
execMethod("456");
} catch (Exception ex) {
// Maybe undo 123
System.out.println("Failed 456");
ex.printStackTrace();
}
} catch (Exception ex) {
System.out.println("Failed 123");
ex.printStackTrace();
}
(假设456依赖于123的成功)
是的。如果 uid
可以由用户输入(它不是 String
文字)。我建议你使用 PreparedStatement
, and a try-with-resources
like
final String sql = "SELECT * from users where uid = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, uid);
try (ResultSet res = ps.executeQuery()) {
while (res.next()) {
// ...
}
}
}
PreparedStatement
(带绑定变量)至少有这些优点
- 可以使用服务器上的
Statement
缓存 - 不容易SQL注射