I have a problem with altering a users password when the password contains a question mark char. I do not encounter this problem with any other char so far, it seems specific to the question mark char.
If i alter a users password in sqlplus using the following sql:
Alter user Stephen identifed by "NewPassword?" REPLACE "OldPassword";
Then it changes the pass successfully and I can login using the new pass 'NewPassword?'.
However if I execute the same SQL via jdbc:
final String query = "ALTER user Stephen identified by \"NewPassword?\" REPLACE \"OldPassword\"";
stmt.executeUpdate(query);
I then cannot log in using the pass 'NewPassword?'.
Checking the hashcodes for the password when entered via sqlplus and jdbc show that they are different.
Somehow when I run the statement in jdbc it is entering something other than 'NewPassword?'.
I don't seem to have any problems with the following passwords:
NewPassword, NewPassword\, NewPassword'. It just seems to be the question mark that is causing problems.
Debugging shows the code point (dec) is 63 for the question mark so it doesn't look like its being changed midway.
Does anyone have any idea what could be causing this behaviour?
I'm at a loss at the moment, I'm considering preventing passes with question marks to bypass this problem for now.
To use JDBC to change the password of an Oracle user you need to do two things:
put the password directly in the SQL string (bind parameters cannot be used),
disable escape processing.
You can't use bind variables because the username and password are not sent to the database as single-quoted strings.
The ? in the SQL string is being taken as a bind variable placeholder, and because of this the SQL string is getting mangled at some point by Oracle JDBC. Disabling escape processing on the statement stops this from happening. Try:
Statement s = conn.createStatement();
s.setEscapeProcessing(false);
s.executeUpdate("ALTER user Stephen identified by \"newPassword?\" replace \"oldPassword\"");
If you are setting the password programmatically, your code should also ensure that the new and old passwords do not contain any " characters, to avoid SQL injection.
Try implementing it using a PreparedStatement and see if you get the same problem. Question marks are used in PreparedStatements as placeholders, so maybe the JDBC driver is getting confused. It shouldn't, but might be worth checking.
PreparedStatement p = conn.prepareStatement("ALTER user Stephen identified by ? replace ?");
p.setString(1, "NewPassword?");
p.setString(2, "OldPassword");
p.execute();
If this works then it's probably a bug in the driver.
Related
Sonarqube is giving me this error:
[BLOCKER] Change this code to not construct SQL queries directly from user-controlled data
Here is my code:
String countSQL;
countSQL = (String.format("SELECT count(*) as total FROM ltid_owner.enty %s",additionalWhereClauses));
jdbcTemplateTMI.queryForObject(countSQL, Integer.class);
In the above code additionalWhereClauses could be something like this shown below which I am building on the fly when the user clicks on the grid to perform filtering on different columns:
additionalWhereClauses = where UPPER(enty_num) like '003%'
Can you please let me know how to resolve this issue?
Your code combines strings into SQL statements. If any of these strings contains user provided input, an attacker can sneak in code to trigger an SQL injection attack and possibly run arbitrary code on your computer (obligatory Bobby Tables reference).
Simple example:
String sql = "SELECT * FROM users WHERE name = '" + name + "' AND password = '" + password + "'";
If I enter ' OR 1=1 -- for the name (and "..." for the password, but that doesn't really matter anymore) the code becomes a valid SQL statement:
SELECT *
FROM users
WHERE name = '' OR 1=1 -- ' AND password = '...'
but the user name / password check is completely disabled.
To avoid this, use prepared statements. They build the SQL command in a way that SQL injection is impossible.
Maybe this never happens in your code as you don't accept user input, but Sonar doesn't know this (and human reviewers won't either). I'd always use prepared statements. Just because your code only passed column headers from a frontend, doesn't mean an attacker cannot manually call your web service endpoints and pass whatever they want, it your code runs as an HTTP endpoint.
I have a requirement. The technology is quite old doesn't support spring at all . It is pure java application with jdbc connection.
Requirement is :
Suppose
select * from employee where empid = <<empid>> and designation = 'Doctor'
I am trying to replace <> with actual int value in java . How I can do it ?
String query = "select * from employee where empid = <<empid>> and designation = 'Doctor'";
if(query.contains("<<empid>>"))
/// Here I want to replace <<empid>> with actual int value in java
Any leads will be helpful
The code you didn't paste, that actually executes the SQL is either [A] a massive security leak that needs serious rewrites, or [B] is using PreparedStatement.
Here's the problem: SQL injection. Creating the SQL string by mixing a template or a bunch of string constants together with a bunch of user input is a security leak. For example, if you try to make SELECT * FROM users WHERE email = 'foo#bar.com' by e.g. String sql = "SELECT * FROM users WHERE email = '" + email + "'";, the problem is, what if the user puts in the web form, in the 'email' field: whatever#foo.com'; DROP TABLE users CASCADE; EXEC 'FORMAT C: /y /force'; --? Then the SQL becomes:
SELECT * FROM users WHERE email = 'whatever#foo.com'; DROP TABLE users CASCADE; EXEC 'FORMAT C: /y /force'; --';
That is legal SQL and you really, really, really don't want your DB engine to execute it.
Each DB engine has its own ideas on what's actually legal, and may do crazy things such as treating curly quotes as real quotes, etc. So, there is no feasible blacklist or whitelist technology you can think of that will properly cover all the bases: You need to ask your DB engine to do this for you, you can't fix this hole yourself.
Java supports this, via java.sql.PreparedStatement. You instead always pass a fully constant SQL string to the engine, and then fill in the blanks, so to speak:
PreparedStatement ps = con.prepareStatement("SELECT * FROM users WHERE email = ?");
ps.setString(1, "foo#whatever.com");
ps.query();
That's how you do it (and add try-with-resources just like you should already be doing here; statements and resultsets are resources you must always close). Even if you call .setString(1, "foo#whatever.com'; DROP TABLE users CASCADE; --"), then it'll simply look for a row in the database that has that mouthful in the email field. It will not delete the entire users table. Security hole eliminated (and this is the only feasible way to eliminate it).
So, check out that code. Is it using preparedstatement? In that case, well, one way or another that code needs to be calling:
ps.setInt(1, 999);
Where ps is the PreparedStatement object created with connection.prepareStatement(...) where ... is either an SQL constant or at least your input string where the <<empid>> was replaced with a question mark and never with any string input from an untrusted source. The 1 in ps.setInt(1, 999) is the position of the question mark (1 = the first question becomes 999), and the 999 is your actual number. It may look like:
if (input instanceof String) {
ps.setString(idx++, (String) input);
} else if (input instanceof Integer) {
ps.setInt(idx++, ((Integer) input).intValue());
} ...
etcetera. If you don't see that, find the setInt invoke and figure out how to get there. If you don't see any setInt, then what you want is not possible without making some updates to this code.
If you don't even see PreparedStatement anywhere in the code, oh dear! Take that server offline right now, research if a security leak has occurred, if this server stored european data you have 72 hours to notify all users if it has or you can't reasonably figure out e.g. by inspecting logs that it hasn't, or you're in breach of the GDPR. Then rewrite that part using PreparedStatement to solve the problem.
I have developed a java program and I need to update and insert the login details of users. I have two textfields created and two buttons name add user and edit the user. when I type the username and password in the two textfields the user added to the database successfully, the error is in the edit user, I want to update the password of the user based on username,
I'm getting SQL error when trying to update the user,
here is my SQL query for updating the password of a user based on his username,
String sql = "UPDATE Admin SET password='"+JT_pass1.getText()+"' WHERE
username = "+JT_username1.getText();
when i execute im getting this error,
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column
'sss' in 'where clause'
"sss" is what I entered to username field,
Mysql database I have admin table which consists of two columns admin and username,
I cannot figure out where am I getting wrong, please any help would be highly appreciated.
Your immediate problem is that you forgot to place single quotes around the username in your query. Hence, the database is interpreting sss as a column. But you should really be using prepared statements:
String query = "UPDATE Admin SET password=? WHERE username = ?";
PreparedStatement update = con.prepareStatement(query);
update.setString(JT_pass1.getText());
update.setString(JT_username1.getText());
update.executeUpdate();
There are many advantages to using prepared statements. First, it will automatically take care of proper escaping of strings and other types of data. In addition, it will prevent SQL injection from happening.
To get this to work, you need to add quotes around the username like so:
String sql = "UPDATE Admin SET password='"+JT_pass1.getText()+"' WHERE
username = '"+JT_username1.getText()+"'";
However, updating the database this way is vulnerable to SQL injection, so it would be much better to use Prepared Statements.
To consider "JT_username1.getText()" as a part of you query string, you have to enclose it under proper quotation.
Same like added "JT_pass1.getText()" between single and double quote, you have to add "JT_username1.getText()" as well.
String sql = "UPDATE Admin SET password='" + JT_pass1.getText() + "' WHERE username = '"+JT_username1.getText()+"'";
I am attempting to use zxJDBC to connect to a database running on SQL Server 2008 R2 (Express) and call a stored procedure, passing it a single parameter. I am using jython-standalone 2.5.3 and ideally do not want to have to install additional modules.
My test code is shown below.
The database name is CSM
Stored Procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE dbo.DUMMY
-- Add the parameters for the stored procedure here
#carrierId VARCHAR(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO dbo.carrier (carrierId, test)
VALUES (#carrierId, 'Success')
END
GO
Jython Script:
from com.ziclix.python.sql import zxJDBC
conn = None
try :
conn = zxJDBC.connect('jdbc:sqlserver://localhost\SQLEXPRESS', 'sa', 'password', 'com.microsoft.sqlserver.jdbc.SQLServerDriver')
cur = conn.cursor()
cur.callproc(('CSM','dbo','DUMMY'), ['carrier1'])
conn.commit()
except Exception, err :
print err
if conn:
conn.rollback()
finally :
if conn :
conn.close()
By using cur.execute() I have been able to verify that the above is successfully connecting to the database, and that I can query against it. However, I have thus far been unable to successfully call a stored procedure with parameters.
The documentation here(possibly out of date?) indicates that callproc() can be called with either a string or a tuple to identify the procedure. The example given -
c.callproc(("northwind", "dbo", "SalesByCategory"), ["Seafood", "1998"], maxrows=2)
When I attempt to use this method, I receive the following error
Error("Could not find stored procedure 'CSM.DUMMY'. [SQLCode: 2812], [SQLState: S00062]",)
It would appear that zxJDBC is neglecting to include the dbo part of the procedure identifier.
If I instead call callproc with "CSM.dbo.DUMMY" as the first argument then I receive this error
Error('An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name. [SQLCode: 1038], [SQLState: S0004]',)
Using a profiler on the database whilst running my script shows that in the second case the following SQL is executed:
use []
go
So it would seem that when using a single string to identify the procedure, the database name is not correctly parsed out.
One of my trial and error attempts to fix this was to call callproc as follows:
cur.callproc(('CSM', '', 'dbo.DUMMY'), ['carrier1'])
This got me only as far as
Error("Procedure or function 'DUMMY' expects parameter '#carrierId', which was not supplied. [SQLCode: 201], [SQLState: S0004]",)
In this case what I think is happening is that zxJDBC attempts to call a system stored procedure (sp_proc_columns) to determine the required parameters for the stored procedure I want to call. My guess is that with the procedure identifier in the incorrect format above, zxJDBC does not get a valid/correct return and assumes no parameters are required.
So basically I am not a bit stuck for ideas as to how to get it to
Use the correct database name
Correctly determine the required parameters using sp_proc_columns
Call my stored procedure with the correct name
all at the same time.
I do have a workaround, which is to use something like
cur.execute('EXEC CSM.dbo.DUMMY ?', ['carrier1'])
However I feel like callproc() is the correct solution, and would likely produce cleaner code when I come to call stored procedures with large numbers of parameters.
If anyone can spot the mistake(s) that I am making, or knows that this is not ever going to work as I think then any input would be much appreciated.
Thanks
Edit
As suggested by i-one, I tried adding cur.execute('USE CSM') before calling my stored procedure (also removing the database name from the procedure call). This unfortunately produces the same Object or Column missing error as above. The profiler shows USE CSM being executed, followed by USE [] so it seems that callproc() always fires a USE statement before the procedure itself.
I have also experimented with turning on/off autocommit, to no avail.
Edit 2
Further information following comments/suggested solutions:
"SQLEXPRESS" in my connection string is the database instance name.
Using double quotes instead of single has no effect.
Including the database name in the connection string (via ;databaseName=CSM; as specified here) and omitting it from the callproc() call leads to the original error with a USE [] statement being fired.
Using callproc(('CSM', 'dbo', 'dbo.DUMMY'), ['carrier1']) gives me some progress but results in the error
Error("Procedure or function 'DUMMY' expects parameter '#carrierId', which was not supplied. [SQLCode: 201], [SQLState: S0004]",)
I'll attempt to investigate this further
Edit 3
Based on the queries I could see zxJDBC firing, I manually executed the following against my database:
use CSM
go
exec sp_sproc_columns_100 N'dbo.DUMMY',N'dbo',N'CSM',NULL,N'3'
go
This gave me an empty results set, which would seem to explain why zxJDBC isn't passing any parameters to the stored procedure - it doesn't think it needs to. I have yet to figure out why this is happening though.
Edit 4
To update the above, the empty result set is because the call should be
exec sp_sproc_columns_100 N'DUMMY',N'dbo',N'CSM',NULL,N'3'
This unfortunately brings me full circle as I can't remove the dbo owner from the stored procedure name in my callproc() call or the procedure won't be found at all.
Edit 5
Table definition as requested
CREATE TABLE [dbo].[carrier](
[carrierId] [varchar](50) NOT NULL,
[test] [varchar](50) NULL
) ON [PRIMARY]
Though completely unaware of the technologies used here (unless some minor knowledge of SQL Server), I will attempt an answer (please forgive me if my jython syntax is not correct. I am trying to outline possibilities here not exact code)
My first approach (found at this post) would be to try:
cur.execute("use CSM")
cur.callproc(("CSM","dbo","dbo.DUMMY"), ["carrier1"])
This must have to do with the fact that sa users always have the dbo as a default schema (described at this SO post)
If the above does not work I would also try to use the CSM database name in the JDBC url (this is very common when using JDBC for other databases) and then simply call one of the two below.
cur.callproc("DUMMY", ["carrier1"])
cur.callproc("dbo.DUMMY", ["carrier1"])
I hope this helps
Update: I quote the relevant part of the link that you can't view
>> Program calls a Stored Procedure - master.dbo.xp_fixeddrives on MS SQL Server
from com.ziclix.python.sql import zxJDBC
def getConnection():
url = "${DBServer.Url}"
user= "${DBServer.User}"
password = "${DBServer.Password}"
driver = "${DBServer.Driver}"
con = zxJDBC.connect(url, user, password, driver)
return con
try:
conn = getConnection()
print 'Connection successful'
cur = conn.cursor()
cur.execute("use master")
cur.callproc(("master", "dbo", "dbo.xp_fixeddrives"))
print cur.description
for a in cur.fetchall():
print a
finally:
cur.close()
conn.close()
print 'Connection closed'
The error you get when you specified the call function like above suggests that the parameter is not passed correctly. So please modify your stored procedure to take a default value and try to call with passing params = [None]. If you see that the call succeeds we must have done something right as far as specifying the database is concerned.
Btw: the most recent documentation suggests that you should be able to access it with your syntax.
As outlined in comments callproc will work only with SELECT. Try this approach instead:
cur.execute("exec CSM.dbo.DUMMY #Param1='" + str(Param1) + "', #carrierId=" + str(carrierID))
Please see this link for more detail.
I have this code :
String check="SELECT COUNT(*) as check FROM recordstudent WHERE STUDENT_ID="+T_STUDENT_ID+" AND COURSE_ID="+T_COURSE_ID+" AND PACKAGE_ID="+T_PACKAGE_ID+" AND ACTIVITY_ID="+T_ACTIVITY_ID+" AND DATE="+T_DATE+ ";";
rs=myStmt.executeQuery(check);
int ch=0;
while(rs.next()){
ch=Integer.parseInt(rs.getString("check"));
}
if(ch==0)
{
String insertRecord="insert into recordstudent"+
"(STUDENT_ID,COURSE_ID,PACKAGE_ID,ACTIVITY_ID,TEST_NAME,DATE,SCORE,TOTAL_MARKS,PERCENTAGE,CORRECT_ANSWER,TOTAL_QUESTIONS,STUDENT_NAME,SCORE_PER_DIVISION,ATTEMPTS)"+
"VALUES("+
"'"+T_STUDENT_ID+"',"+
"'"+T_COURSE_ID+"',"+
"'"+T_PACKAGE_ID+"',"+
"'"+T_ACTIVITY_ID+"',"+
"'"+T_TEST_NAME+"',"+
"'"+T_DATE+"',"+
"'"+T_SCORE+"',"+
"'"+T_TOTAL_MARKS+"',"+
"'"+T_PERCENTAGE+"',"+
"'"+T_CORRECT_ANSWERS+"',"+
"'"+T_TOTAL_QUESTIONS+"',"+
"'"+T_STUDENT_NAME+"',"+
"'"+T_SCORE_PER_DIVISION+"',"+
"'"+t+"'"
+");";
myStmt.execute(insertRecord);
}
This snippet should insert the data in database only if the ch=0 .But I am getting this error:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:
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
'check FROM recordstudent WHERE STUDENT_ID=11 AND COURSE_ID=2 AND PACKAGE_ID=11 A'
at line 1
Can Anyone help me and solve my problem ?
Fundamentally: don't build your SQL this way. I notice that you've put quotes round the values in the "insert" SQL statement - but not in the "select" one. That's the start of the problem - but you shouldn't be including values like this in your SQL to start with. You should use parameterized SQL via PreparedStatement, and set values for the parameters. Benefits:
You can see your actual SQL more easily, so you'll be able to spot syntax errors. (This is basically keeping your code separate from your data.)
(Very important) You won't be open to SQL injection attacks
You won't need to worry about conversion issues for numbers, dates and times etc
There are other problems in your SQL (such as spaces and check being a reserved word in MySQL), but the very first thing you should fix is how you use values. Until you've done that, your code is inviting security problems.
(You should then start using more conventional variable names than T_STUDENT_NAME etc, but that's a different matter.)
check is a reserved word. Surround it with backticks: `check`
Try this
SELECT COUNT(*) as 'check' FROM recordstudent....
instead of
SELECT COUNT(*) as check FROM recordstudent....
I think check is a keyword