Hiding body of stored procedure? - oracle

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).

Related

CREATE TABLE statement in Oracle with the existence check

This question is inspired by this.
As stated, I don't want a solution from PL/SQL. I want a 1 or 2 SQL statements that will check for table existence and if its not exist - create it.
Such statement(s) will be plugged into C++ application (not a script) and so I want a plain SQL solution. If such solution is not exist (please say so), I'd like to have a simple string I can plug into C++ code and use either SQLExecute() or a native Oracle client API to execute such a string.
Trying to google for a solution I am getting a results that can be used either in the shell script or a stored procedure. As I explain here and in the previous question - my situation is completely different - I work in C++ and want an appropriate solution.
There is no single SQL statement that will create a table only if it does not exist in Oracle 11g.
It is not obvious to me why you're objecting to a PL/SQL based solution. If you're using raw ODBC calls in C++, you can pass a PL/SQL block to SQLPrepare just as you would pass a plain SQL statement. Given that PL/SQL blocks work almost exactly like a pure SQL statement, it would be unusual to categorically reject a PL/SQL based solution.
If you are going to categorically reject PL/SQL, you can certainly take the logic from any of the PL/SQL based solutions and implement that in a couple of SQL statement executed from your application. For example, you can query dba_| all_| user_tables (depending on your privileges, whether you are creating tables in other schemas, etc.) to determine whether the table exists and then conditionally execute your DDL
select owner, table_name
from dba_tables
where owner = <<schema that will own the table>
and table_name = <<name of the table>>
If that returns no rows you can then execute your DDL.
Of course, you can also just execute your DDL statement and catch the ORA-00955 name is already used by an existing object error in C++.

Using regexp_replace to prevent SQL injection

We have thousands of oracle packages that contain a map_products procedure.
We have a table that stores the list of oracle packages a customer would like that map_products run for.
The process that runs them uses dynamic SQL like this:
select sanitize(package_name)
into v_package_name
from custom_plugins
where id = p_id;
execute immediate '
begin
'||v_package_name||'.map_products;
end;
';
The sanitize function above is meant to prevent SQL injection.
Here is the function definition:
function sanitize(p_string in varchar2) return varchar2
is
begin
return regexp_replace(upper(p_string),
'(ALTER|MERGE|CREATE|SELECT|INSERT|UPDATE|DELETE|MODIFY|DROP|ENABLE|DISABLE|;)');
end;
Now we realize this is a dangerous approach in the long run and are planning to redo the entire process. However, for the time being, is there any easy way that this regexp_replace can be circumvented allowing SQL injection?
More specifically, we want to make sure that a semicolon cannot be passed in. Does the above ensure that?
Use the string:
DRDROPOP your_package_name
The replace will only replace DROP once leaving you with:
DROP your_package_name
I suggest whitelisting instead of regular expressions.
Check the input against the system tables.
select object_name
from dba_objects
where owner = 'SYS'
and object_type = 'PACKAGE'
and object_name = :p_string;
If you can't find a match, then it isn't a known package, so don't use it.
I think removing the ; will be a first approach to avoid the sql injection. But please consider this possible strategy:
Extract with regexp a valid package name from the input(for example, checking that you have alphanumeric characters, or "_", or any other character allowed in a package name but nothing else).
With the output from previous step, check that the package is actually an object in the database (querying user_object).
At this point you will have a valid package name (if any) and you could use it in the dynamic statement.
You already said that your approach was dangerous. I just want to make sure that you're aware that it'd be problematic with a package with a name containing any of the words in your regexp (salaryUPDATEr, for example)
As the other posters above have commented blacklisting is going to be quite easy to bypass.
Using whitelist validation is always ideal. If that's not feasible, and since this is Oracle, the best option is to use the built in dbms_assert.enquote_name - this safely enquotes the value (and checks for embedded quotes).
For more info on DBMS_ASSERT see:
https://oracle-base.com/articles/10g/dbms_assert_10gR2#ENQUOTE_NAME
Or for much more in depth on preventing SQL injection see:
http://www.oracle.com/technetwork/database/features/plsql/overview/how-to-write-injection-proof-plsql-1-129572.pdf
You can use the DBMS_ASSERT package.
Since the 10g version, Oracle provides the DBMS_ASSERT package. It contains functions that can be used to validate user input.
Example (SQL Injection attempt)
SELECT description FROM products WHERE name=DBMS_ASSERT.ENQUOTE_LITERAL('abc'' OR 1=1--');
ERROR RETURNED.
ORA-06502: PL/SQL: numeric or value error
You can find more information at link.

PLSQL "give" script but not allow users to read

I'm new to pl/sql and my question is: is it possible to "compile" a script in sql plus or sql developer and give the file to other person in order to allow other to execute the code but not allowing them to read the code?
It sounds like you are talking about the Oracle wrap utility (a separate command-line application that is part of your Oracle client install and not a part of SQL Developer) or the dbms_ddl.wrap function which you could invoke from SQL Developer. These create obfuscated statements that will create a stored procedure (or package or function) that behaves normally but where the text in the data dictionary is not human readable. The wrap utility doesn't provide perfect security-- there are unwrapping tools and presentations on the internet that would let an attacker unwrap the code you hand them. And you can often figure out what the unwrapped code is really doing by looking at other data dictionary views (v$sql will show the unwrapped SQL statements that are executed for example) or by tracing a session.
It depends also of definition of the word give. You can store PL/SQL code in the database. Give users right to execute it, to see the source code of the package header, but not to see the source of package body. But of course DBAs can read it, They can also trace it (even if it is wrapped).
Also note that PL/SQL packages are wrapped in a different way than PL/SQL procedures. As of 11g packages are wrapped using simple one-to-one byte substitution. While for PL/SQL procedures, there is stored obfuscated bytecode of DIANA virtual machine. AFAIK there is no accessible unwrap for PL/SQL procedures, it is much harder to reverse engineer.

Use Parameter with no need of creating stored procedures

Is it possible to use or add parameters on a simple query without the need of creating stored procedures or function? Are Bind Variables possible without creating a stored procedures?
where are you running the code from? If your running from a language like Java / VB you would use a stored procedure or prepared statement.
If using from Sql *Plus terminal or other Sql UI
SQL> variable deptno number
SQL> exec :deptno := 10
SQL> select * from
emp where deptno = :deptno;
From a high level language like Java or VB use stored procedures, following is from the article you linked to so not sure why you are asking this?
In fact, the answer to this is actually quite simple. When you put
together an SQL statement using Java, or VB, or whatever, you usually
use an API for accessing the database; ADO in the case of VB, JDBC in
the case of Java. All of these APIs have built-in support for bind
variables, and it's just a case of using this support rather than just
concatenating a string yourself and submitting it to the database.
For example, Java has PreparedStatement, which allows the use of bind
variables, and Statement, which uses the string concatenation
approach. If you use the method that supports bind variables, the API
itself passes the bind variable value to Oracle at runtime, and you
just submit your SQL statement as normal. There's no need to
separately pass the bind variable value to Oracle, and actually no
additional work on your part. Support for bind variables isn't just
limited to Oracle - it's common to other RDBMS platforms such as
Microsoft SQL Server, so there's no excuse for not using them just
because they might be an Oracle-only feature.
Not sure why you are asking as this information is there on the site http://www.akadia.com/services/ora_bind_variables.html
Well, assuming you will perform queries using an external programming language, prepared statements will make the job.
See http://en.wikipedia.org/wiki/Prepared_statement

Call data-specific stored procedure from Oracle procedure

I have a situation where I have an Oracle procedure that is being called from at least 3 or 4 different places. I need to be able to be able to call custom-code depending on some data. The custom-code is customer-specific - so, customer A might want to do A-B-C where customer B might want to do 6-7-8 and customer C doesn't need to do anything extra. When customers D...Z come along, I don't want to have to modify my existing procedure.
I'd like to be able to enter the customer-specific procedure into a table. In this existing procedure, check that database table if a custom-code procedure exists and if so, execute it. Each of the customer-code procedures would have the same parameters.
For instance:
My application (3+ places) calls this "delete" procedure
In this delete procedure, look up the name of a child-procedure to call (if one exists at all)
If one exists, execute that delete procedure (passing the parameters in)
I know I can do this with building a string that contains the call to the stored procedure. But, I'd like to know if Oracle 10g has anything built in for doing this kind of thing?
Do each of your customers have their own database? If so the best option would be to use conditional compilation. This has the advantage of not requiring dynamic SQL. Have the main program always call the custom procedure, and use CC flags to vary the code it contains.
Otherwise, Oracle does have a Rule Engine but it is not really intended for our use.
The final solution that we went with was to store the name of a procedure in a database table. We then build the SQL call and use an EXECUTE statement.
Agree with APC's answer and just to expand on it, in this white paper if you look for "Component based installation" it describes a similar problem solved by using conditional compilation.
Your solution seems reasonable given the requirements, so I voted it up.
Another option would be to loop through the results from your table look-up and put calls to the procedures inside a big case statement. It would be more code, but it would have the advantage of making the dependency chain visible so you could more easily catch missing permissions and invalid procedures.

Resources