Ensure that a SQL query is READ-only - sql

What would be the best way to ensure that a SQL query won't alter the data of a database?
In my scenario, you don't have access to the database layer and can only do this logic on the application layer.
Would you recommend using a gem, a ruby custom script?

You can manage the permissions of the users so that they have access for reading the database but they don't have access to alter the database (i.e. not able to insert, update and delete). If you are using mysql, for instance, you can easily do this in phpmyadmin or equivalent tool.
Update based on your change. Even if you only have access through the application you are still connected to the database as a user who has or does not have privileges to update, delete, insert or select and as such the only way to ensure no such queries are executed is to alter that user's permissions.

A simple but far from foolproof method is to employ a blacklist of words that cannot be in the query, such as insert, update, etc.
Alternatively, you could use a parser on the sql query that will provide you with the necessary information to derive whether or not to allow the query.
I would take option 1 only as a last resort or if your checking needs are relatively simple.

On the database layer, make sure that the user the Rails app is accessing the database as only has the access that you desire, perhaps only SELECT.

Sequel has support for read only slave databases with a writable master database. Read-only slaves handle SELECT queries, other queries are done by the master database.
Maybe you can just setup master database as nil?
Another approach could be using hooks (before_save) to prevent writing to the database.

Related

User-generated SQL Query

I'm developing a data warehouse using Ruby on Rails and I should allow the user to perform arbitrary SELECT queries on the application database.
I know this is what you usually SHOULDN'T do, but it's an interface my client actually needs (I can't think of all the possible queries the user might want to do and translate them to ActiveRecord queries). There could be complex joins and sub-queries and so on.
I'd rather do this (integrate it to my app) than let them access the DB via pgAdmin (I'm using postgresql).
My question is: what is the safest way of doing this? I should be able to escape anything like INSERT, UPDATE, DROP TABLE, etc...
I'm thinking of getting the query string and sanitizing these "dangerous" words and then using ActiveRecord::Base.connection.execute(sanitized_sql_string).
Is this a reasonable approach?
The safest way would be to let Postgres handle this security for you. Create a new user:
CREATE USER Reader; -- Your Rails app should logon with this user
Then, explicitly grant SELECT permissions on the objects you want them to be able to query:
GRANT INSERT ON TableFoo TO Reader;
GRANT INSERT ON TableBar TO Reader;
Then, they'll be able to run arbitrary SELECT queries from these two tables, but if they try an INSERT, they'll get Permission denied. You can then trap those security exceptions and handle them in your UI appropriately.
Create the application then create the database.
After this, in your database configuration (database.yml), connect to the database with some non-default user, say lame_user. Create this lame_user on your RDBMS, in your case PostgreSQL, and grant him only SELECT permissions on all of your tables.
You will now have the user postgres and the lame_user that can access your database, but only postgres can do all the stuff.
If the user tries to do anything besides SELECT's, an error will occur.
Resuming: Make this application constraint a database thing. It will be easier.

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.

How to monitor and log all the SQL insert commands

I am using Oracle SQL Dev 2.1.1.64
I work with application that uses oracle database for storage.
Is there any way in SQL Dev. to monitor and log all the insert commands that are "coming" from the web application into database? Can you tell me how to do that?
audit insert table by <web-application-user> by access
should get you started.
Be sure to set the parameters audit_trail and audit_file_dest as you need them.
After that, you find the operations either in sys.aud$ or in the directory specified by audit_file_dest.
There is also fine grained auditing into which you might take a look, but from your question, using fine grained auditing (FGA) would seem to be overkill.
You can write a trigger for the tables you want to monitor. If you are only interested on the insert queries coming from the Web Application, you can check on the trigger for some specific username/schema accessing the table, and use that username as your web application credentials.
Alternatively you can also use Oracle's AUDIT feature. It requires a little bit of Oracle Database Administration knowledge to implement though...
You could query v$SQL, but you would need to have the relevant GRANTS to enable you to do this.
For long running sessions you can also monitor progress using v$session_longops
hope this helps you.
Create a trigger that writes to a journaling table whenever a change of data in the table happens (insert, update, delete).
Before delete, after insert, after update triggers are what you want.
It won't specifically log only the web application, but if you log the user making the change you will be able to filter on that when viewing the data.

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.