How to design a immutable append-only database? - sql

for a project I need to implement a database which is immutable and only allows new entries. Editing or deleting entries should be impossible in any case.
I was thinking about a database which allows editing and deleting only for admins (so only me). However, I'm unsure if that is 100% safe or if it's possible to illegally get admin rights and forge the data. So the best solution would be to have a database which does not offer editing or deleting in the first place.
Suggestions appreciated! Thanks

PostgreSQL supports, since 9.5, Row Security Policies, which allow you to define select, insert, delete and update policies depending on the user, and/or some fields values in the table. You might find what you search there.

The simplest way is to GRANT separated rights to INSERT/UPDATE/DELETE to users but it may be insufficient for some business rules. However, many DBMS (SQL Server for example) support INSTEAD OF triggers which can quietly bypass any DELETE/UPDATE and process INSERT depending on your custom criteria implemented in trigger code.
You can also define an updateable view having INSTEAD OF triggers to insert-only data.

Related

SQL Server Auditing Alternatives with Application User Tracking

I'm looking for an auditing solution that does exactly what Change Data Capture (CDC) does, except I need it to also track the application user that made the change. I'm currently using SQL Server 2012 Enterprise and may be upgrading to 2014 later this year.
We already have an auditing solution in place that leverages Delete, Insert, and Update triggers, but some new requirements might force us to update every audit trigger and corresponding audit table. Given various problems we've run in to with that solution over the years, this seems like as good a time as any to reevaluate and potentially replace the solution.
To give you an idea of what I'm currently working with (and may be able to leverage), we use a stored procedure (ConnectionInitialize) to store a user id with a SPID in a table (ApplicationUser) and then we delete the row using another stored procedure (ConnectionReset) once we're done making our deletes, inserts, and updates.
Were we to use CDC, I looked into adding a trigger to something like the cdc.lsn_time_mapping table, but I couldn't find a way to map the LSN back to the SPID (and therefore the user id) that was being used. This also presented some other issues in that CDC is always a little bit behind.
I looked into SQL Server Audit a little bit, but that presented some challenges of its own. We're using Transparent Data Encryption (TDE) to appease some of our security requirements, but SQL Server Audit looks like it'd need a separate encryption strategy; that and I'm more interested in the columns than in the actual SQL statements. Even so, these aren't deal-breakers for me, so I'm still looking into it.
Given what I'm trying to accomplish, does anyone have any feedback or recommendations?
By itself, CDC doesn't meet the requirements. The reason being is that CDC only grabs changes to your data, not any underlying context under which those changes were made. You can, however, get what you're looking for if you're willing to tag your data with some audit columns. The basic idea is that you append a column to your table (or to a different table if you aren't able to modify the actual table for whatever reason) and populate it with the user who last modified the record (pretty simple to do via an insert/update trigger). Once that is actual data, you can consume it however you need to (CDC being one possible mechanism).
Late answer but hopefully useful.
There is a third party tool, ApexSQL Audit, capable of meeting your requirements. My previous company is using it for years and they have been satisfied with it.
There is a helpful comparison article you can read to find more details about audited data, auditing mechanisms, integrity protection etc, for both CDC & Audit tool at one place.

Database support for immutable fields

We're about to start a new project and I'm breaking down the models at the moment. Most of the entities I'm modelling are meant to be immutable.
While I can control this to a certain extent at the code level by using something like django-immutablemodel, I'd be more comfortable if I could enforce this at the database level as well.
I'm planning to use postgresql although would be willing to consider alternatives if they supported this. From what I can tell the two main ways to do this currently are:
Add a set of triggers to make sure that immutable fields aren't modified
Enforce the immutability through user rights (i.e. don't give user update rights to columns that you want immutable)
I'd be interested if anyone has tried these methods and can comment on them or knows a better way to do this.
For some fields I want to be an effective write-once, so if the field is NULL allow it to be updated to a value, but never allow a field with a value to be updated. That would suggest I need to go down the trigger route.
If most of the entities (tables? you mention columns later on) are immutable then place that information in separate tables and revoke all access privileges to these tables. Create a second table for modifiable data, again with all privileges revoked, and link the two with a key. Now create a view that is built from both tables and create an INSTEAD OF INSERT OR UPDATE OR DELETE trigger which restricts updates to the modifiable table.
There are other solutions possible, such as with column privileges, but the above solution has the nice side effect that you can optimize read-only table access and that you only have to back up the few tables that are modifiable.

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.

Ensure that a SQL query is READ-only

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.

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.