CREATE USER and CREATE ROLE as PreparedStatement with ? placeholder - jdbc

I am trying to issue a CREATE USER statement against a HSQLDB database from Java code in a way that allows the use of parameters.
However, the following line:
connection.prepareStatement("CREATE USER ? PASSWORD ?;");
throws an exception:
java.sql.SQLSyntaxErrorException: unexpected token: ? in statement [CREATE USER ? PASSWORD ?;]
at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
at org.hsqldb.jdbc.JDBCPreparedStatement.<init>(Unknown Source)
at org.hsqldb.jdbc.JDBCConnection.prepareStatement(Unknown Source)
at (somewhere in my code)
The same happens for
connection.prepareStatement("CREATE ROLE ?;");
Of course, I could assemble my string without ?, by pasting the values directly into the statement, though that would open up some potential for SQL injection.
So I am wondering why placeholders are not working. Are they supported in these statements at all? Or am I missing something else?

In general, databases only allow parameters in DML, not in DDL. And in DML, it is only allowed for values. In the case of CREATE USER and CREATE ROLE, you aren't dealing with values (at least not for the user or role name), so parameterization is not possible for those. This is similar to not allowing parameters for the table name or column name in a select statement.
In theory, something like the password in CREATE PASSWORD is a value and could be parameterized, but in practice this isn't possible (at least, not that I'm aware of), as all DDL is handled as non-parameterizable.
As a minor form of protection against SQL injection, since JDBC 4.3 (introduced in Java 9), you can use Statement.enquoteIdentifier to quote identifiers, and Statement.enquoteLiteral for literals like passwords. These methods have a default implementation, but if you're using a platform with non-standard identifier quotes (e.g. like MySQL), then you must make sure it is actually overridden (which isn't the case in current versions of MySQL Connector/J AFAIK).

Related

FireDAC "table or view does not exist" when insert into ORACLE TABLE Delphi Belin 10.1 upd 2

We are migrating our codebase from Delphi XE3 with FireDAC 8.0.5 to Delphi Berlin 10.1 Upd 2 with FireDAC 15.0.1 (Build 86746). Everything is working smoothly using MS Sql Server, but using ORACLE it has been another history.
Throughout the application source code we use lots of TAdQuery with sql instructions like
AdQuery1.Sql.Text := 'SELECT FIELD1, FIELD2 FROM TABLE1';
In order to insert a record, we use Append or Insert methods, like this
AdQuery1.Insert;
//or
AdQuery1.Append;
Just after invoking its Post method, the component internally creates an INSERT sql statement, that goes like this
INSERT INTO TABLE1 (FIELD1, FIELD2) VALUES(:FIELD1, :FIELD2)
So the record gets inserted successfully.
Now, using TFdQuery in Delphi Berlin, the component internally creates an INSERT sql statement, like this
INSERT INTO USERNAME.TABLE1 (FIELD1, FIELD2) VALUES(:FIELD1, :FIELD2)
Failing with a [FireDAC][Phys][Ora] ORA-00942: table or view does not exist
This happens because in our Oracle database, TABLE1 is created in a schema called MAIN_SCHEMA, and we access it by using a public synonym.
Trying to find a workaround, we compared FireDAC source code, finding that
in Delphi XE3, the unit uADDAptManager.pas, on its function TADDAptTableAdapter.GetUpdateRowCommand, calls oConn.CreateCommandGenerator(oCmdGen, nil);
in Delphi Berlin, the unit FireDAC.DApt.pas, on its function TFDDAptTableAdapter.GetUpdateRowCommand
calls oConn.CreateCommandGenerator(oCmdGen, GetSelectCommand);
Whenever that second parameter (called ACommand: IFDPhysCommand) is not nil, the name of the table is returned concatenating the user name (in a function called TFDPhysCommandGenerator.GetFrom).
If we add 'MetaCurSchema=MAIN_SCHEMA' to the TFdConnection params, it works with the applications that not use a pooled connection, but We have several process that use a pooled connection with the same params, even MetaCurSchema param, but it doesn't work
What can we do?
thanks for your help
What I understand is that you would do better making the connection avoid the use of any schema name, rather than specifying it. Also, keeping in mind that you already use public synonyms.
So, according to the documentation:
Full object names
FireDAC supports full object names, which include the catalog and/or schema names.
When a short object name is specified to StoredProcName, TableName, etc, they will be expanded into the full object names, using the current catalog and/or schema names. To override or avoid usage of the current catalog and/or schema names, use the MetaCurCatalog and MetaCurSchema connection definition parameters. For example:
[Oracle_Demo]
DriverID=Ora
...
MetaCurCatalog=*
MetaCurSchema=*
~ Source: Object Names (FireDAC) - docWiki
MetaCurSchema
Specifies the current schema for the application. If not specified, then its value will be received from the DBMS. When an application is asking for metadata and do not specify a schema name, then FireDAC will implicitly use the current schema.
If MetaCurSchema is '*', then schema names will be me omitted from the metadata parameters.
~ Source: Common Connection Parameters (FireDAC) - docWiki
That asterisk (*) should do the trick, let us know if that's the case.

load SQL statements from a file using clojure.java.jdbc

The REST call is sending the branchId and emplId to this exec-sql-file method. I am passing these as a parameter. I am not able to execute the SQL statement when I pass branch_id = #branchid and empl_id = #emplid. But when I hardcode the branch_id = 'BR101' and empl_id = 123456 then it is working. Any suggestion how to get the branch_Id and empl_Id in my some-statements.sql?
(defn exec-sql-file
[branchid emplid]
(sql/with-db-connection (db-conn)
(sql/db-do-prepared conn
[branchid emplid (slurp (resource "sql/some-statements.sql"))])))
some-statements.sql have this query
DELETE from customer where branch_id = #branchid and empl_id = #emplid;
I am executing this from REPL as
(exec-sql-file "BR101" 123456)
I grab the code snippet from the below post.
Is it possible to patch load SQL statements from a file using clojure.java.jdbc?
There is no simple way to do this as your approach requires that you have to provide parameters to multiple SQL statements in one run. Another issue is that Java's PreparedStatement (used under the hood by clojure.java.jdbc) doesn't support named parameters, so even if parameters to multiple SQL statements done using a single prepared statement would have to be provided for every placeholder (?).
I would suggest following solutions:
use multiple prepared statements (so separate clojure.java.jdbc/execute! calls) for each of the SQL statement you want to execute wrapped in a single transaction (each SQL could be read from a separate file). You could also use some helper library like YeSQL to make loading your SQL statements from external files and exposing them as functions you could call as ordinary Clojure functions. It would be simple but if you change the number of statements you would like to execute, then you need to change your code
create a stored procedure and call them from Clojure providing the parameters - this will define an interface for some DB logic which will be defined on the DB side. Unless you change the interface of your stored procedure you can modify its implementation without changing your Clojure code or redeployment
implement your own logic of interpolating named parameters into your "multistatement" SQL file. The issue is to appropriately escape parameters' values so your code is not vulnerable to SQL injection. I would discourage this solution.

security concern over passing password in sql statement or callable satement

I am planning to keep password hash in my database rather than plain text. What my concern is when I execute my query from JDBC in a prepared statements like:
SELECT username FROM users WHERE username = 'userName'
and password = dbms_crypto.hash(utl_raw.cast_to_raw('password'),3);
or
INSERT INTO users VALUES ('username', dbms_crypto.hash(utl_raw.cast_to_raw('passowrd'),3);
or If I call PLSQL procedure which expect me to pass the plaintext password and then thse procedures will have queries like above in their body. My concern can somebody tap my passwords sent from my server to my database through these queries via JDBC. Is it better to use prepared statement or plsql procedure to overcome this security concern? Or should I hash my passwords using my java code first and then pass these password for insertion or selection?
The only way to overcome the security issue that you quote is to pre-hash your passwords server-side prior to sending it over the wire.
That's best practice.
HOWEVER dbms_crypto.hash is not secure for password storage and you should not be using it. Instead, you should be using BCrypt with an appropriate salt and cost. Generate the bcrypt hash in your server code, then send it to the database already hashed (for inserts) or pull the hash from the database using the username (for selects).
Additionally, I would like to point out that it's a severe problem if an attacker can get close enough to your database to see the queries you're running on it. While I am a fan of defense-in-depth, so you should protect against the possibility, if that's actually happening that's a massive issue.
I would recommend either encrypting the password before you send the sql with java encryption or secure your SQLNet.
For more information on securing SQLNet refer to orafaq.com they have a short and good description: http://www.orafaq.com/wiki/Network_Encryption
BTW: these SQL statements are not "prepared".
ircmaxell's answer is the best solution.
If for some reason you are unable to pre-hash the value, and must pass the plaintext password to the database, you should at least ensure the database does not cache the statement that includes the plaintext password. A specific statement can be purged from the shared pool, i.e. GV$SQL, with the following code:
--Remove a SQL statement from the shared pool.
begin
for cached_sql in
(
select *
from gv$sql
where lower(sql_fulltext) like
'insert into users values%dbms_crypto.hash(utl_raw.cast_to_raw%'
) loop
sys.dbms_shared_pool.purge(cached_sql.address||','
||cached_sql.hash_value, 'C', 1);
end loop;
end;
/

OracleDatareader seems to execute an update statement

I am using oracle client 11.2.0
Dll version 4.112.3.0
We have a page in our application where people can give a sql statement and retreive results. basically do an oracle command.executereader
Recently one of my team members gave an update statement as a test and it actually performed an update on a record!!!!
Anyone who has encountered this?
Regards
Sid.
It is a normal (albeit a bit unsettling) behavior. ExecuteReader is expected to execute the sql command provided as CommandText and build a DbDataReader that you use to loop over the results.
If the command doesn't return any row to read is not something that the reader should prevent in any case. And so it is not expected that it checks if your command is really a SELECT statement.
Think for example if you pass a stored procedure name or if you have multiple sql batch to execute. (INSERT followed by a SELECT)
I think that the biggest problem here is the fact that you allow an arbitrary sql command typed by your users to reach the database engine. A very big hole in security. You should, at least, execute some analysis on the query text before submitting the code to the database engine.
I agree with Steve. Your reader will execute any command, and might get a bit confused if it's not a select and doesn't return a result set.
To prevent people from modifying anything, create a new user, grant select only (no update, no delete, no insert) on your tables to that user (grant select on tablename to seconduser). Then, log in as seconduser, and, create synonyms for your tables (create synonym tablename for realowner.tablename). Have your application use the seconduser when connecting to the DB. This should prevent people from "hacking" your site. If you want to be of the safe side, grant no permissions but create session to the second user to prevent him from creating tables, dropping your views and similar stuff (I'd guess your executereader won't allow DDL, but test it to make sure).

Hiding body of stored procedure?

I defined a role and grant it with only connect to database and execute a specific stored procedure. Users have this role can see the body of procedure when execute this query;
select * from ALL_SOURCE where NAME = 'procedureName';
Procedure takes a VARCHAR2 parameter and uses it with a select query. Is that a security issue? Should i hide it somehow or escape the parameter?
Generally, it would only be a security issue if your procedure was subject to SQL injection. The fact that you talk about escaping the parameter implies that you may be doing dynamic SQL and may be vulnerable to SQL injection attacks. If that's the case, you need to fix the procedure, not hide the source.
If your stored procedure is implementing some business logic that you consider proprietary, you could potentially wrap the code so that it is obfuscated in the data dictionary. If you do that, however, make absolutely sure that you your source code in source control because there is no way to unwrap code once you've wrapped it (strictly speaking, there are various techniques that an attacker can use to recover most of the wrapped source if they really wanted to, but it's reasonably secure).

Resources