0

I've been looking around and can't seem to find a solid answer to this. I was wondering if putting a string literal in executeQuery() is still prone to SQL injection.

So lets say I have this code:

  Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/","root","password");
  Statement stmt = conn.createStatement();

  ResultSet res = stmt.executeQuery("SELECT * from users where uid = "+uid);

Is this prone to a SQL injection?

Another question is, is just making the method that uses this code only throw an SQLException, and then trying and catching in main acceptable?

For example:

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

Is this the standard or correct way of using SQL exceptions? I've never really worked with SQL and especially not Java and SQL. The tutorials I've read seem to only lay it out one way, so I'm pretty unsure of myself.

Alex
  • 2,145
  • 6
  • 36
  • 72
  • *"Is this prone to a SQL injection?"* - Yes, you have no control over what `uid` actually contains. *"Another question is, is just making the method that uses this code only throw an SQLException, and then trying and catching in main acceptable?"* Yes and no, you should at least wrap the contends of `execMethod` in `try-finally` to ensure that you are closing the resources you open (or use a `try-with-resources` for Java 7) – MadProgrammer May 08 '15 at 03:25
  • You should only ask one question per question. – Mark Rotteveel May 08 '15 at 06:39

3 Answers3

1

Short answer : yes.

You do not appear to be doing any kind of input validation so there isn't anything stopping uid from being something like "105 or 1=1"

You should probably use PreparedStatements tutorial here

PreparedStatement stmt = conn.prepareStatement("SELECT * from users where uid = ?")
stmt.setString(1, uid);

..same as before

Also you don't close the statement or the connection which should be done in a finally block incase an exception is thrown

dkatzel
  • 31,188
  • 3
  • 63
  • 67
1

Is this prone to a SQL injection?"

Yes, you have no control over what uid might actually contain.

See Using Prepared Statements for more details

Another question is, is just making the method that uses this code only throw an SQLException, and then trying and catching in main acceptable?"

Yes, but you should at least wrap the contends of execMethod in try-finally to ensure that you are closing the resources you open (or use a try-with-resources for 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
            }
        }
    }
}

See The try-with-resources Statement for more details

But, I would only catch the SQLException for EACH call, not batch them together, as you won't know what failed and what succeeded

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

(assuming that 456 is dependent on the success of 123)

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I've always heard that even doing a couple of try / catch statements will seriously slow down the program. Is that something I should be worried about in this case? – Alex May 08 '15 at 03:32
  • Personally, I've not heard this, but you would need to take into consideration based on needs. If you only processing small number of queries or have a reasonable delay between queries, what's the harm, when you gain the knowledge in what succeeded and what failed - but you've have to balance based on the context of the problem you are having. – MadProgrammer May 08 '15 at 03:35
  • And `try-with-resource` can be chained, for example `try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/", "root", "password"); PreparedStatement stmt = conn.prepareStatement("SELECT * from users where uid = ?")) {`, but I compounded it to make it more readable – MadProgrammer May 08 '15 at 03:36
  • 4
    try is practically free. It's the throw that's expensive. See this other SO post for details: http://stackoverflow.com/questions/16451777/is-it-expensive-to-use-try-catch-blocks-even-if-an-exception-is-never-thrown – dkatzel May 08 '15 at 03:36
  • @MadProgrammer Normally you could chain the `try-with-resources` but in this case you need to bind the `uid`. – Elliott Frisch May 08 '15 at 03:37
  • @ElliottFrisch *face plant* Thanks forgot about that, updated the comment, least get rid of one level – MadProgrammer May 08 '15 at 03:38
  • @MadProgrammer Sorry did the comment update? It looks the same for me – Alex May 08 '15 at 03:55
  • @Alex Yes, I took out `ResultSet res = stmt.executeQuery()` (from my comment about compound `try-with-resources`) – MadProgrammer May 08 '15 at 03:56
  • @MadProgrammer Awesome. Thank you for all of the advice and help :) I appreciate it greatly. – Alex May 08 '15 at 03:57
1

Yes. If uid can be entered by a user (it's not a String literal). I suggest you use a 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()) {
             // ...
        }
    }
}

The PreparedStatement (with bind variable) has at least these advantages

  1. It can use the Statement cache on the server
  2. It is not prone to SQL Injection
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
  • While the "If `uid` can be entered by a user" is true, I think it's an assumption that should never be made if possible. It may be the case that a value isn't currently entered by a user, but it is in the future so leaving things as they are is just a vulnerability waiting to happen. – Michael Mior Sep 22 '22 at 14:24