Does wrapping a query in SELECT protect you completely in Postgres - postgresql

Given a client library that can only execute one statement in a batch, if you run
query.exec_sql("SELECT * FROM (" + sql + ")")
Are there any vectors where sql can run anything but a SELECT ?
Are there any other ways to temporarily de-elevate a connection so it can only perform SELECT?
Note: It looks like SET ROLE solves this problem, but the the issue I have is that I am unable to create a role upfront in an easy way.

While you can put data-modifying statements in queries by embedding INSERT/UPDATE/DELETE statements in CTEs, they're only allowed at the top level, so that's not an issue.
You can, however, invoke a function, which could contain just about anything. Even if you ran this in a read-only transaction, a function could potentially elevate it to read-write.
But the solution is simple: If you don't want to allow the caller to do something, don't give them permission to do it. Create a user with only the GRANTs they need, and you can execute sql as-is.
Without the ability to define permissions, the closest you're going to get is probably a read-only transaction and/or an explicit rollback after the query, but there will still be holes you can't plug (e.g. you can't roll back a setval() call).

If the sql string came from a third party then it can be used to SQL injection. I'm not sure if that is what you are asking because it is too basic for a 56k points user to ask. Sorry if that is not the case. The string could be:
some_table; insert into user_table (user_id, admin_privilege) values (1, true);

Related

What does this select statement actually do?

I'm reviewing log of executed PostgreSQL statements and stumble upon one statement I can't totally understand. Can somebody explain what PostgreSQL actually do when such query is executed? What is siq_query?
select *
from siq_query('', '21:1', '', '("my search string")', False, True, 'http://siqfindex:8080/storediq/findex')
I'm running PostgreSQL 9.2
siq_query(...) is a server-side function taking 7 input parameters (or more). It's not part of any standard Postgres distribution I know (certainly not mainline Postgres 9.2), so it has to be user-defined or part of some extension you installed. It does whatever is defined in the function. This can include basically anything your Postgres user is allowed to do. Unless it's a SECURITY DEFINER function, then it ca do whatever the owner of the function is allowed to do.
The way it is called (SELECT * FROM), only makes sense if it returns multiple rows and/or columns, most likely a set of rows, making it a "set-returning function", which can be used almost like a table in SQL queries.
Since the function name is not schema-qualified, it has to reside in a visible schema. See:
How does the search_path influence identifier resolution and the "current schema"
Long story short, you need to see the function definition to know what it does exactly. You can use psql (\df+ siq_query), pgAdmin (browse and select it to see its definition in the SQL pane) or any other client tool to look it up. Or query the system catalog pg_proc directly:
SELECT * FROM pg_proc WHERE proname = 'siq_query';
Pay special attention to the column prosrc, which holds the function body for some languages like plpgsql.
There might be multiple variants of that name, Postgres allows function overloading.

Is it possible to get explain plan with bind variables in DB2?

With Oracle, the syntax is:
explain plan for
select * from users WHERE user_name = :user_name AND user_dob = :user_dob
Is it possible to do the same in DB2? The statement below does not seem to work.
explain plan with snapshot for
select * from users WHERE user_name = :user_name AND user_dob = :user_dob
Thank you.
The answer may depend on your DB2 version and platform, which you chose not to share with us for some reason. This works fine on DB2 for LUW (v10.1, but I'm sure it would work with v9.7 and up):
$ db2 "explain plan with snapshot for select * from syscat.schemata where schemaname = :blah"
DB20000I The SQL command completed successfully.
You may want to try replacing named parameter markers with questions marks.
Apparently, the answer is in the IBM website, but it is not easy to make sense of.
http://publib.boulder.ibm.com/infocenter/db2luw/v9/index.jsp?topic=%2Fcom.ibm.db2.udb.admin.doc%2Fdoc%2Fr0000952.htm
FOR explainable-sql-statement
Specifies the SQL statement to be explained. This statement can be any
valid CALL, Compound SQL (Dynamic), DELETE, INSERT, MERGE, SELECT,
SELECT INTO, UPDATE, VALUES, or VALUES INTO SQL statement. If the
EXPLAIN statement is embedded in a program, the
explainable-sql-statement can contain references to host variables
(these variables must be defined in the program). Similarly, if
EXPLAIN is being dynamically prepared, the explainable-sql-statement
can contain parameter markers.
But it does not tell you what "parameter markers" are, so you have to go and search for it.

How is this code prone to SQL injection?

I was reading PostgreSql documentation here, and came across the following code snippet:
EXECUTE 'SELECT count(*) FROM mytable WHERE inserted_by = $1 AND inserted <= $2'
INTO c
USING checked_user, checked_date;
The documentation states that "This method is often preferable to inserting data values into the command string as text: it avoids run-time overhead of converting the values to text and back, and it is much less prone to SQL-injection attacks since there is no need for quoting or escaping".
Can you show me how this code is prone to SQL injection at all?
Edit: in all other RDBMS I have worked with this would completely prevent SQL injection. What is implemented differently in PostgreSql?
Quick answer is that it isn't by itself prone to SQL injection, As I understand your question you are asking why we don't just say so. So since you are looking for scenarios where this might lead to SQL injection, consider that mytable might be a view, and so could have additional functions behind it. Those functions might be vulnerable to SQL injection.
So you can't look at a query and conclude that it is definitely not susceptible to SQL injection. The best you can do is indicate that at the level provided, this specific level of your application does not raise sql injection concerns here.
Here is an example of a case where sql injection might very well happen.
CREATE OR REPLACE FUNCTION ban_user() returns trigger
language plpgsql security definer as
$$
begin
insert into banned_users (username) values (new.username);
execute 'alter user ' || new.username || ' WITH VALID UNTIL ''YESTERDAY''';
return new;
end;
Note that utility functions cannot be parameterized as you indicate, and we forgot to quote_ident() around new.username, thus making the field vulnerable.
CREATE OR REPLACE VIEW banned_users_today AS
SELECT username FROM banned_users where banned_date = 'today';
CREATE TRIGGER i_banned_users_today INSTEAD OF INSERT ON banned_users_today
FOR EACH ROW EXECUTE PROCEDURE ban_user();
EXECUTE 'insert into banned_users_today (username) values ($1)'
USING 'postgres with password ''boo''; drop function ban_user() cascade; --';
So no it doesn't completely solve the problem even if used everywhere it can be used. And proper use of quote_literal() and quote_ident() don't always solve the problem either.
The thing is that the problem can always be at a lower level than the query you are executing.
The bound parameters prevent garbage to manipulate the statement into doing anything other than what it's intended to do.
This guarantees no possibility for SQL-injection attacks short of a Postgres bug. (See H2C03's link for examples of what could go wrong.)
I imagine the "much less prone to SQL-injection attacks" amounts to CYA verbiage were such a thing were to arise.
SQL injection is usually associated with large data dumps on pastebin.com and such scenario won't work here even if the example used contatenation not variables. It's because that COUNT(*) will aggregate all data you'd be trying to steal.
But I can imagine scenarios where count of arbitrary record would be sufficiently valuable information - e.g. number of competitor's clients, number of sold products etc. And actually recalling some of the really tricky blind SQL injection methods it might be possible to build a query that using COUNT alone would allow to iteratively recover actual text from the database.
It would be also much easier to exploit on a database sufficiently old and misconfigured to allow the ; separator, in which case the attacker might just append a completely separate query.

SQL Server temp tables via MS Access

Well I've been using #temp tables in standard T-SQL coding for years and thought I understood them.
However, I've been dragged into a project based in MS Access, utilizing pass-through queries, and found something that has really got me puzzled.
Though maybe it's the inner workings of Access that has me fooled !?
Here we go : Under normal usage, I understand the if I create a temp table in a Sproc, it's scope ends with the end of the SProc, and is dropped by default.
In the Access example, I found it was possible to do this in one Query:
select top(10) * into #myTemp from dbo.myTable
And then this in second separate query:
select * from #myTemp
How is this possible ?
If a temp table dies with the current session, does this mean that Access keeps a single session open, and uses that session for all Queries executed ?
Or has my fundamental understanding of scope been wrong all this time ?
Hope someone out there can help clarify what is occurring under the hood !?
Many Thanks
I found this answer of a kind of similar question:
Temp table is stored in tempdb until the connection is dropped (or in the case of a global temp tables when the last connection using it is dropped). You can also (and it is a good proctice to do so) manually drop the table when you are finished using it with a drop table statement.
I hope this helps out.

DB2 Equivalent to SQL's GO?

I have written a DB2 query to do the following:
Create a temp table
Select from a monster query / insert into the temp table
Select from the temp table / delete from old table
Select from the temp table / insert into a different table
In MSSQL, I am allowed to run the commands one after another as one long query. Failing that, I can delimit them with 'GO' commands. When I attempt this in DB2, I get the error:
DB2CLI.DLL: ERROR [42601] [IBM][CLI Driver][DB2] SQL0199N The use of the reserved
word "GO" following "" is not valid. Expected tokens may include: "".
SQLSTATE=42601
What can I use to delimit these instructions without the temp table going out of scope?
GO is something that is used in MSSQL Studio, I have my own app for running upates into live and use "GO" to break the statements apart.
Does DB2 support the semi-colon (;)? This is a standard delimiter in many SQL implementations.
have you tried using just a semi-colon instead of "GO"?
This link suggests that the semi-colon should work for DB2 - http://www.scribd.com/doc/16640/IBM-DB2
I would try wrapping what you are looking to do in BEGIN and END to set the scope.
GO is not a SQL command, it's not even a TSQL command. It is an instruction for the parser. I don't know DB2, but I would imagine that GO is not neccessary.
From Devx.com Tips
Although GO is not a T-SQL statement, it is often used in T-SQL code and unless you know what it is it can be a mystery. So what is its purpose? Well, it causes all statements from the beginning of the script or the last GO statement (whichever is closer) to be compiled into one execution plan and sent to the server independent of any other batches.