Permissions required to allow arbitrary sql to be executed safely - sql

I want to create an SQL sandbox that will allow users to execute arbitrary SELECT queries at a PostGIS database. Essentially, I want to allow users access to psql to play with.
Obviously this is a security disaster if write access is allowed. How can I create a system such that querying data is allowed, but there is no reasonable possibility of a user:
Compromising the data in the database
Gaining broader access to the server
Crippling the system with a query like SELECT * from long_table, long_table, long_table, long_table, long_table, long_table, long_table that will take a life-time to execute
Please be as specific as possible in your answer.

Problems #1 and #2 are handled via explicit GRANTs and REVOKEs of permissions as others have noted.
As for #3,
ALTER ROLE <rolename> SET statement_timeout = '60000'
has always worked well for me. This terminates any query that executes for longer than 1 minute (60000 ms). We discovered this after having a couple of user-written queries in phpPgAdmin cause problems...

Well you just really need to CREATE a ROLE and then GRANT read only access explicitly to the things you want to allow. Anything you don't grant, they can't do (as long as they're not a superuser).
If you've granted readonly access and they're not a superuser, they shouldn't be able to gain access to the underlying system. That is not to say you shouldn't install postgres as an unprivileged user, you should - simply that it shouldn't be necessary to accomplish what you listed.
Ok, you edited your post to include issuing crazy queries. I don't believe postgres currently has a way to limit query resources per user.

You can install postgres as an unprivileged user, and run it that way. This way you take advantage of the existing system permissions to restrict what people can do with the database, including isolating their access to just their own database. See instructions at the bottom of this page:
http://www.postgresql.org/docs/current/interactive/tutorial-start.html
If you automate some part of this, say give people a 'setup postgres' command to run, voila.

For #3 could you write some code that monitors query activity and kill those queries you deem CRAZY based on some criteria using the system views in postgre?

#3 can't be prevented when the user can execute his own piece of SQL. You need a (small) application that executes predefined SQL. Not even VIEW's can help you here, everybody can join a couple of views to cripple your system.

Related

How to prevent SQL injection attack when a sql query is passed in from the UI

I have a Java application that does a POST with the sql query that is typed in the UI and is executed using JDBC. Since the query is user defined, I'm unable to find a way to prevent the SQL injection issue. For instance if this is the query the user issues :
select * from test_table where id=123
a POST is done with this string to the servlet and this is executed as a query. Is there anyway to get around this since there is no restriction on what user can send in?
Thanks
Technically if the user is allowed to write the entire query, it's not an injection attack risk, it's simply an attack risk
Run the query using a database user that has permission only to carry out the types of operations you deem acceptable on the tables you're willing to give access to.
For example, only permit SELECT on tableX, tableY and tableZ. No DML, no DDL and no selecting from any other table
If your dbms of choice doesn't allow fine grained control in this way then instead execute a regular batch script that creates another database containing only a few tables. Permit your users to query this new db. If it does get wrecked it will soon be dropped and replaced by a working one with updated data, by the script. This is also beneficial if placed on another server, it stops your live system from being innocently DOSed by a user executing a duff query that takes up all resource on the server
SQL injection would be passing select * from test_table where id=123 in place of a parameter.
Not sure exactly what information you are letting the application use, but I would suggest granting access only to a specific schema. That would provide a consistent security model.
As others have suggested, this is not SQL injection - I call this a "designed in" SQL injection. How you deal with it depends on the use case:
Design a separate interface that does not require the full SQL statement
As Caius suggested, if you can limit the privs in the DB account to only do what the user can do, that would limit the damage
If this is an administrative interface, you may want to limit the usage of this interface to "trusted" users. If you go that route, you want to be very careful to document that users with this privilege have full access to the database, and provide an auditing mechanism to make sure that that list of users is well known.
It is not realistically possible to limit the SQL statement through validation - its a powerful language, especially in the context of modern databases.
See also this related question
Is there anyway to get around this since there is no restriction on what user can send in?
I'm not sure what you mean by "get around." Is it not the design of this application to allow users to run any query?
If you want to prevent them from running unauthorized queries, then you'll have to implement some Java code in the servlet to check the query and decide whether it's one they're authorized to run.
Some people do this by whitelisting a specific set of known queries. Just match the user's input query against the whitelist.
If they can run a given query with a variety of different constant values, then replace constant values with a ? in both the whitelisted form and in a copy of the user's input SQL query.
If they can run a variety of different queries, like with optional clauses and stuff, so that it's impossible to make a whitelist of finite length, then you'll have to implement a SQL parser in your Java servlet and some kind of business rule engine to decide if their query is authorized before you run it against the real database.
At this point, it seems easier to change the application front-end so that users are not allowed to submit arbitrary SQL queries!

Secure way to accept SQL query via form input

So I'm about to create a simple site where users can input their own SQL queries, which I will be running on the server side.
I'm aware of SQL injection attacks and assume this could be fairly risky thing to do.
But (if there is any) what would be a safe way to allow this feature?
e.g. I can think of the following rules I can enforce.
Allow users to only "SELECT" - never allow UPDATE, DELETE (or anything else).
Allow users to only access certain tables (if I know them).
Are there any other security measures I should take?
As well as security issues, performance might be a problem as pointed out by ElectricLlama. You might want to look into getting the query's execution plan in advance, and refusing to run if it looks like the query would be too expensive:
How do I obtain a Query Execution Plan?
Further to the above make sure the user is added to the db_datareader groups and that will make them read only. I guess you will be using a single user to perform that database actions.
You still cause a database failure if the user accidentally does a couple of cross joins:
SELECT *
FROM Table1,Table2,Table3
WHERE Table1.Field1=Table2.Field2
-- Oops I forgot to enter the Table3 Join condition
-- so now I get a cross join which will cause havoc
-- If the table is of appreciative size
But anyway it's still risky! Someone will find a security hole!

GRANT Database Permissions for specific tables and the validity of this as a security practice?

my question is rather simple.
Can i grant permissions on a database table wise? something in the lines:
User Management has permission to select, update, insert and delete on table Projects
User Supervisor has permission to select, update, insert on table Projects
User Colaborator has permission to select on table Projects
If so, I could set up a system to create database users based on the levels of access of my application, much like the examples above.
Is it a valid mechanism to use this to secure a application?
is it worth on a real world application?
i've used PHP with Oracle and MySQL, but I'm look for a database/language agnostic answer, but any example would be useful.
pushing my luck a bit, what about per record permission granting?
also, what about table schemas, are they a more acceptable then table based permissions?
The main problem with using database security would be that you need separate connections for each user rather than being able to use a "service user" for the connection from your application server to your DB server. That would mean that you would no longer be able to use database connection pooling have to "connect" and "disconnect" from the database for every user request, which is not very efficient as connections are relatively expensive.
Having said that, there is good reason for using separate users in the database, such as DATA_USER (which the application server connects as) and DATA_OWNER (which owns all the tables but is used only for DB maintenance) and then only give DATA_USER the permissions that it needs to, e.g. only select on a lookup table. By separating DATA_USER and DATA_OWNER you can add an additional level of confidence that your application won't issue DDL commands (e.g. dropping a table).
Answer to part 1:
Yes as long as you handle the responses correctly.
Part 2:
It's not as good as implementating security in the application layer, as most applications will need flexibility in the solution (what if you want a user to get increased privledges, have to code in lots of alter/deny/grant scripts)
Part 3: (Speaking from purely MSSQL) Row-level permissions aren't possible. Create custom views for this purpose.

Disable all queries in SQL Server that don't use named parameters?

It seems that one could stop all threat of Sql injection once and for all by simply rejecting all queries that don't use named parameters. Any way to configure Sql server to do that? Or else any way to enforce that at the application level by inspecting each query without writing an entire SQL parser? Thanks.
Remove the grants for a role to be able to SELECT/UPDATE/INSERT/DELETE against the table(s) involved
Grant EXECUTE on the role for stored procedures/functions/etc
Associate the role to database user(s) you want to secure
It won't stop an account that also has the ability to GRANT access, but it will stop the users associated to the role (assuming no other grants on a per user basis) from being able to execute queries outside of the stored procedure/functions/etc that exist.
There are only a couple ways to do this. OMG Ponies has the best answer: don't allow direct sql statements against your database and instead leverage the tools and security sql server can provide.
An alternative way would be to add an additional tier which all queries would have to go through. In short you'd pass all queries (SOA architecture) to a new app which would evaluate the query for passing on to sql server. I've seen exactly one company do this in reaction to sql injection issues their site had.
Of course, this is a horrible way of doing things because SQL injection is only one potential problem.
Beyond SQL Injection, you also have issues of what happens when the site itself is cracked. Once you can write a new page to a web server it becomes trivial to pass any query you want to the associated database server. This would easily bypass any code level thing you could put in place. And it would allow the attacker to just write select * from ... or truncate table ... Heck, an internal person could potentially just directly connect to the sql server using the sites credentials and run any query they wanted.
The point is, if you leverage the security built into sql server to prevent direct table access then you can control through stored procedures the full range of actions availble to anyone attempting to connect to the server.
And how do you want to check for that? Queries sometimes have constant values that would just as easy be added to the query. For instance, I have a database that is prepared to be multi lingual, but not all code is, so my query looks like this:
SELECT NAME FROM SOMETABLE WHERE ID = :ID AND LANGUAGEID = 1
The ID is a parameter, but the language id isn't. Should this query be blocked?
You ask to block queries that don't use named parameters. That can be easily enforced. Just block any query that doesn't specify any parameters. You can do this in your application layer. But it will be hard to block queries like the one above, where one value is a parameter and the other one isn't. You'll need to parse that query to detect it, and it will be hard too.
I don't think sql server has any built in features to do this.

In Oracle: how can I tell if an SQL query will cause changes without executing it?

I've got a string containing an SQL statement. I want to find out whether the query will modify data or database structure, or if it will only read data. Is there some way to do this?
More info: In our application we need to let the users enter SQL-queries, mainly as part of the applications report system. These SQL queries should be allowed to read whatever they like from the databse, but they shouldn't be allowed to modify anything. No updates, deletes insert, table drops, constraint removals etc.
As of now I only test whether the first word in the string is "select", but this is too constricting and too insecure.
You should grant only select privileges on your tables for the login used by the application to be sure.
Create a new user for that part of the application that only has select privileges. Bear in mind that you'll also need to create synonyms for all the tables/views that that "read-only" user will be able to view.
The "regular" part of your application will still be able to do other operations (insert, update, delete). Just the reporting will use the read-only user.
As Horacio suggests, it is also a good idea/practice to add "wrapper" views that only expose what you want to expose. Some sort of "public API". This can give you flexibility if you need to change the underlying tables and don't want to/can't change the reports to the new definitions of said tables. This might, however, be seen as a lot of "extra work".
I agree with others that the right thing to do is use a separate schema with limited access & privileges for those queries that should be read-only.
Another option, however, is to set the transaction read-only before executing the statement entered by the user (SET TRANSACTION READ ONLY).
Create VIEWS to expose the data to end users, this is worthy because of three things:
The end user doesn't know how really your database look like.
You may can provide a simpler way to extract some pieces of data.
You can create the view with a read-only constraint:
CREATE VIEW items (name, price, tax)
AS SELECT name, price, tax_rate
FROM item
WITH READ ONLY;
Something that has worked well for me in the past, but may not fit your situation:
Use stored procedures to implement an API for the application. All modifications are done via that API. The procedures exposed to the front end are all complete units of work, and those procedures are responsible for rights enforcement.
The users running the front end application are only allowed to call the API stored procedures and read data.
Since the exposed API does complete units of work that correspond to actions the user could take via the GUI, letting them run the procedures directly doesn't get them any additional ability, nor allow them to corrupt the database accidently.
SELECT * FROM table FOR UPDATE works even with only SELECT privilege, and can still cause a lot of damage. If you want to be safe, the read only transactions are better.