I am coding an interface which manages a database with all DML and some DDL features. One feature should be, that an admin can add users to the database with specified priviledges.
I know how to grant priviledges in sql i only need it done via a java application.
So is there a way to get this done safely? It probably will work with a simple executeUpdate
String cu = "create user"+userName+" identified by "+pw+";";
Statement stmt;
stmt = con.createStatement();
stmt.executeUpdate(query);
but this opens my ass for injections. Is there a way to get this done safely by a preexisting method ?
Please help me out, mighty stackoverflow community :)
Yes, there is a better way of doing this. Use PrepredStatement instead of Statement.
You need gap and quation ' for password,
String cu = "create user "+userName+" identified by '"+pw+"';";
|
|_put gap here
Related
I'm having a weird problem with an Grails application accessing data. Going deeper I've isolated the problem to a plain java8 small application using PreparedStatement.executeQuery vs Statement.executeQuery.
Consider the following snippet of code:
// executes in milliseconds
directSql = "select top(10) * from vdocuments where codcli = 'CCCC' and serial = 'SSSS' ORDER BY otherField DESC;";
stmt = con.createStatement();
rs = stmt.executeQuery(directSql);
// More than 10 minutes
sqlPrepared = "select top(10) * from vdocuments where codCli = ? and serial = ? ORDER BY otherField DESC;";
PreparedStatement pStatement = con.prepareStatement( sqlPrepared );
pStatement.setString(1, "CCCC");
pStatement.setString(2, "SSSS");
rsPrepared = pStatement.executeQuery();
Same query.
Data comes from a view on SqlServer (2008, I think, have no access right now) from a table with more than 15 Million records. There are indexes for all needed fields and the same query (the first one) executed from console runs also quite fast.
If I execute the slow PreparedStatement query without the ORDER clause it also runs fast.
It looks clear to me that for any cause the database it's not using indexes and make a full scan when using preparedStatement, but maybe I'm wrong so I'm open to any idea.
I thought maybe the driver (sqlserver official latest and jtds has been tested) was holding the data waiting for any kind of EOF from connection but I've checked with tcpdump on my side and no data is received.
I can't find why this is happening so any idea will be welcomed.
Thank you in advanced!
I've finally found a solution, at least in for my case. I got it here http://mehmoodbluffs.blogspot.com.es/2015/03/hibernate-queries-are-slow-sql-servers.html . Telling (driver? sqlServer?) not to send parameters as Unicode have resolved the problem.
Current connection string it's now:
String connectionUrl = "jdbc:sqlserver://server:port;databaseName=myDataBase;sendStringParametersAsUnicode=false";
And now both direct queries and preparedStatements runs at millisecond speed.
Thank you #DanGuzman for your suggestions!
Currently i'm writing a JDBC application to manage a MySQL database. I have the delete, insert and select methods functioning with the correct queries. I'm having trouble with the Update method. When using using the following code I receive a MySQL error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near "",Street",Town",City",PostCode",Age",email",RunningFee'false'Where PID=" at line 1...
private void updateData()
{
Connection con;
try
{
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(
"jdbc:mysql://localhost/snr","root","");
String sql = "Update participant Set password='"+txtpassword.getText()+"'," +
"lastName='"+txtlastName.getText()+"',firstName='"+
txtfirstName.getText()+"',HouseNumber'"+txtHouseNumber.getText()+"',Street'"+txtStreet.getText()+"',Town'"+txtTown.getText()+"',City'"+txtCity.getText()+"',PostCode'"+txtPostCode.getText()+"',Age'"+txtAge.getText()+"',email'"+txtemail.getText()+"',RunningFee'"+cbRunningFee.isSelected()+"' Where PID='"+txtPID.getText()+"'";
Statement statement = con.createStatement();
statement.execute(sql);
createMessageBox("Updated Successfully");
clearControls();
}
catch(Exception e)
{
createMessageBox(e.getMessage());
}
}
Is there something wrong with my SQL query?
Yes, your query is wrong. You're missing = on a great big bunch of set column/value pairs.
(And please consider using prepared statements and bind variables, SQL injection is just not something you want to be open to.)
Yes there is something wrong with the query. Your way of building query is vulnerable to SQL Injection. Use Parameterized Queries instead of concatenating text like that.
Read this article: Preventing SQL Injection in Java
Not only is your query incorrect, but it may also open you to SQL Interjection Attacks.
You need to parameterize your query by replacing the pasted-in values with question marks, preparing the statement, and executing it. See the tutorial that I linked.
Finally, storing a password as plain text is a very, very bad idea.
String sql = "UPDATE participant SET "+
"password=?, lastName=?, firstName=?, HouseNumber=?, Street=?, Town=?, "+
"City=?,PostCode?,Age=?,email=?,RunningFee=? "+
"WHERE PID=?";
PreparedStatement upd = con.prepareStatement(sql);
upd.setString(1, txtpassword.getText());
upd.setString(2, txtlastName.getText());
// ... and so on
upd.executeUpdate();
con.commit();
You are forgetting some = in your query.
Try
String sql = "Update participant Set password='"+txtpassword.getText()+"'," +
"lastName='"+txtlastName.getText()+"',firstName='"+
txtfirstName.getText()+"',HouseNumber='"+txtHouseNumber.getText()+"',Street='"+
txtStreet.getText()+"',Town='"+txtTown.getText()+"',City='"+txtCity.getText()+
"',PostCode='"+txtPostCode.getText()+"',Age='"+txtAge.getText()+"',email='"+
txtemail.getText()+"',RunningFee='"+cbRunningFee.isSelected()+
"' Where PID='"+txtPID.getText()+"'";
The error 'you have an error in your SQL syntax' is from the sql server and indicates that yes, you do have an error in your query. In these cases I often find it useful to print the constructed query itself, just to check that it is being constructed correctly.
In your case I believe the problem is that you are missing a bunch of "="s, you also probably need to escape your single quotes in the java so they are passed through correctly (replace ' with \').
I'm searching for a Java standard library to escape strings before using them in a SQL statement. This is mainly to prevent errors and to prevent SQL injection, too.
Unfortunately, I will not be able to use prepared statements as is is suggested in a lot of other threads.
Is there any standard library I can use?
I've seen StringEscapeUtils at Apache Commons but I really don't know if this is state of the art.
Thank you very much in advance!
This is a non-trivial problem and a critical one because of SQL injection security issues. I would instead consider using SQL ? type arguments instead of escaping. For example, to search for a particular string:
Instead of doing:
SELECT * FROM accounts
WHERE name = 'escapedstring1' AND password = 'escapedstring2'
I'd use:
SELECT * FROM accounts WHERE name = ? AND password = ?
You will then need to pass in the injected strings (without any escaping needed) as arguments to your SQL methods. Here's how to do it using JDBC. Not sure if that would apply to you.
Something like:
String statement = "SELECT * FROM accounts WHERE name = ? AND password = ?";
try {
PreparedStatement stmt = databaseConnection.prepareStatement(updateString);
// notice that it is 1 based, not 0 (ick)
stmt.setString(1, name);
stmt.setString(2, password);
ResultSet results = stmt.executeQuery();
Here's how ORMLite, my ORM library, does it as an example using a select argument.
Hope this helps.
You can use Apache Commons, it's the very mature project.
I'm trying to determine the best way to ping a database via JDBC. By 'best' I mean fast and low overhead. For example, I've considered executing this:
"SELECT 1 FROM DUAL"
but I believe the DUAL table is Oracle-specific, and I need something more generic.
Note that Connection has an isClosed() method, but the javadoc states that this cannot be used to test the validity of the connection.
With JDBC 4 you can use isValid(int) (JavaDoc) from the Connection Interface. This basically does the trial statement for you.
Some driver implement this by sending the correct dummy SQL to the database and some directly uses low level operations which reduces the parsing overhead.
However beware of the timeout, some drivers (DB/400 and Oracle Thin) do spawn a new time thread for each invocation, which is not really acceptable for most Pool validation scenarios). And Oracle also does not seem to use a prepared statement, so it’s kind of relying on the implicit cache.
Yes, that would be Oracle-only, but there is no generic way to do this in JDBC.
Most connection pool implementations have a configuration parameter where you can specify the SQL that will be used for ping, thus pushing the responsiblity to figure out how to do it to the user.
That seems like the best approach unless someone comes up with a little helper tool for this (of course, it precludes using potentially even faster non-SQL-based methods like Oracle's internal ping function)
MySQL has a nice mechanism, documented in this SO answer. From the answer:
"/* ping */ SELECT 1"
This will actually cause the driver send a ping to the server and return a fake, light-weight, result set.
Having said that, #eckes answer is the best (using JDBC 4's Connection.isValid(int)).
I'm not aware of a generic solution, either. For IBM's UDB on iSeries (and perhaps other DB2 systems) it would be
select 1 from SYSIBM.SYSDUMMY1;
You could try to get the db name from the connection meta data and execute a matching sql staement. E.g.
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
con = dataSource.getConnection();
String dbProductName = con.getMetaData().getDatabaseProductName();
Statement st = con.createStatement();
if ( "PostgreSQL".equalsIgnoreCase(dbProductName) ) {
rs = st.executeQuery("select version();");
} else if ( "Oracle".equalsIgnoreCase(dbProductName) ) {
rs = st.executeQuery("select 1 from dual");
} else {
...
}
} catch ( Exception ex ) {
System.out.prinln("DB not reachable");
} finally {
// close statement, connection etc.
...
}
I may be out to lunch on this one, but could you simply execute some non-sense query, such as:
SELECT * FROM donkey_giraffe_87
I don't know very much about JDBC's error handling, but perhaps you could check to see if the database is at least telling you that the table does not exist. If JDBC's error codes are vendor-specific, the Spring Framework has some utilities for mapping these codes to more meaningful exceptions.
I am working a Airsoft application.
I'm trying to add records to a MS Access Database via SQL in Java. I have established a link to the database, with the following:
try
{
//String Driver = "sun.java.odbc.JdbcOdbcDriver";
Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");
Connection conn = DriverManager.getConnection("jdbc:ucanaccess://" + URL,"","");
Statement stmt = conn.createStatement();
System.out.println("Connection Established!");
ResultSet rs = stmt.executeQuery("SELECT * FROM AirsoftGunRentals");
tblRent.setModel(DbUtils.resultSetToTableModel(rs));
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, "Error");
}
I am using Ucanaccess to access my MS database. It is reading the database and is displaying to a JTable. However, I need to create three JButtons to add, delete and update the table. I have tried to code the add button, and I have tried to add a record, but it crashes and gives me errors.
try
{
//String Driver = "sun.java.odbc.JdbcOdbcDriver";
Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");
Connection conn = DriverManager.getConnection("jdbc:ucanaccess://" + URL,"","");
Statement stmt = conn.createStatement();
System.out.println("Connection Established!");
String Query= "INSERT INTO AirsoftGunRentals(NameOfGun, Brand, TypeOfGuns, NumberOfMagazines,Extras,NumberAvailable,UnitRent)"+
"VALUES('"+pName+"','"+pBrand+"','"+pTypeOfGun+"','"+pNumMags+"','"+pExtras+"','"+pNumberAvail+"','"+pRent+"');";
ResultSet rs = stmt.executeQuery(Query);
JOptionPane.showMessageDialog(null, "Success!");
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, "Error");
}
I have attempted all three, hoping for a result. But am still getting big errors. The only difference between the buttons is that one adds, one deletes and one updates the table. Other then that, the code is the same, minus variables.
As Brahim mentionned it, you should use stmt.executeUpdate(Query) whenever you update / insert or delete data. Also with this particular query, given your String concatenation (see end of line), there is no space between the ")" and the "VALUES" which probably causes a malformed query.
However, I can see from your code that you are not very experienced with such use-cases, and I'd like to add some pointers before all hell breaks loose in your project :
Use PreparedStatement instead of Statement and replace variables by placeholders to prevent SQL Injection.
The code that you are using here is extremely prone to SQL injection - if any user has any control over any of the variables, this could lead to a full database dump (theft), destruction of data (vandalism), or even in machine takeover if other conditions are met.
A good advice is to never use the Statement class, better be safe than sorry :)
Respect Java Conventions (or be coherent).
In your example you define the String Query, while all the other variables start with lower-case (as in Java Conventions), instead of String query. Overtime, such little mistakes (that won't break a build) will lead to bugs due to mistaking variables with classnames etc :)
Good luck on your road to mastering this wonderful language ! :)
First add a space before the quotation marks like this :
String Query= "INSERT INTO AirsoftGunRentals(NameOfGun, Brand, TypeOfGuns, NumberOfMagazines,Extras,NumberAvailable,UnitRent) "+
" VALUES('"+pName+"','"+pBrand+"','"+pTypeOfGun+"','"+pNumMags+"','"+pExtras+"','"+pNumberAvail+"','"+pRent+"');";
And use stmt.executeUpdate(Query); instead of : stmt.executeQuery(Query);in your insert, update and delete queries. For select queries you can keep it.
I managed to find an answer on how to add, delete and update records to a MS Access DB. This is what I found, after I declared the connection, and the prepped statement. I will try to explain to the best I can. I had to add values individually using this:
(pstmt = Prepped Statement Variable)
pstmt.setWhatever(1,Variable);
And it works fine now. I use the same method to delete and update records.
This is the basic query format:
String SQLInsert = "INSERT INTO Tbl VALUES(NULL,?,?,?,?)";
The NULL in the statement is the autonumber in the table. and .setWhatever() clause replaces the question marks with the data types. Thus manipulating the database.
Thank you everyone for all your contributions. It helped a lot, and made this section a lot more understandable.