Why isn't row level security enabled for Postgres views? - sql

I need strict control of the reading and writing of my Postgres data. Updatable views have always provided very good, strict, control of the reading of my data and allows me to add valuable computed columns. With Postgres 9.5 row level security has introduced a new and powerful way to control my data. But I can't use both technologies views, and row level security together. Why?

Basically because it wasn't possible to retroactively change how views work. I'd like to be able to support SECURITY INVOKER (or equivalent) for views but as far as I know no such feature presently exists.
You can filter access to the view its self with row security normally.
The tables accessed by the view will also have their row security rules applied. However, they'll see the current_user as the view creator because views access tables (and other views) with the rights of the user who created/owns the view.
Maybe it'd be worth raising this on pgsql-hackers if you're willing to step in and help with development of the feature you need, or pgsql-general otherwise?
That said, while views access tables as the creating user and change current_user accordingly, they don't prevent you from using custom GUCs, the session_user, or other contextual information in row security policies. You can use row security with views, just not (usefully) to filter based on current_user.

You can do this from PostgreSQL v15 on, which introduced the security_invoker option on views. If you turn that on, permissions on the underlying tables are checked as the user who calls the view, and RLS policies for the invoking user are used.
You can change existing views with
ALTER VIEW view_name SET (security_invoker = on);

The row level security policy can still be applied in the WHERE clause of the view. For example:
WHERE my_security_policy_function(person_id)

Related

How to design a immutable append-only database?

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.

Distribute same WebI Report to different audiences with different filters

I just started using SAP Web Intelligence and I have a couple of reports ready to deploy for end users. The report includes a "Region" field, and I want each user to be able to only see data in their respective "Region". I know I can make several copies of the report and filter by each region, but this will make it difficult to maintain. Does anyone know how I can use the same Report but set different filters for the end-users?
Thanks
You can use row-level security. This is done in the universe, and will cause a condition to be inserted into the report's SQL to restrict results based on the user's credentials.
The "out-of-the-box" method for implementing row-level security is accessed in UDT via Tools -> Manage Security -> Manage Access Restrictions, or in IDT via Window -> Security Editor. The interfaces are very different, but accomplish the same result -- you select a group and create a condition that should be applied for all members in that group.
You can also implement row-level security without using the built-in security managers described above. If you have a table in your database that contains a mapping of user ID to region, the logic can be implemented right in the universe.
Note that in both of the above solutions, the security is implemented by adjusting the report's SQL. If the users have the ability to modify SQL, then they can override the security. This may or may not be a concern for you, but it is worth being aware of.
Is the report being published as pdf or xls/xlsx?
If so, you can create a (one) generic report and use [Region] as a prompted query filter.
When scheduling the report you can set the prompt to match your audience, and publish directly to them via mailing list also set up scheduling the report.
You will need one schedule per region/audience.
This keeps maintenance at a reasonable level as there's only one report to maintain.
//C

Is it possible to change a database by SQL SELECT statement?

We want to allow to an administrator (only) to execute an SQL SELECT statement via Web UI.
Please note that the administrator is allowed to view all information in a database.
What are security risks with this approach?
Is it possible to change somehow a database by SQL SELECT statement (any record or table)?
added
RDBMS is PostgreSQL
We want to allow to an administrator (only) to execute an SQL SELECT statement via Web UI. Please note that the administrator is allowed to view all information in a database.
What are security risks with this approach? Is it possible to change somehow a database by SQL SELECT statement (any record or table)?
Well, how do you propose to let them execute SELECT statements? PostgreSQL doesn't have user-level statement privileges, it has privileges on individual database objects.
In theory you can absolutely modify the database with SELECT. Just look at PostgreSQL's function list. Not to mention the user-defined functions. The most obvious case is of course nextval, which advances a sequence, or setval which sets a sequence's position.
However, everything requires rights on the associated database objects. If you only GRANT the SELECT right on a table (or some subset of the column's tables) then the user won't be able to modify the data in that table directly. Nor does PostgreSQL provide functions to bypass that restriction built-in. So simply creating a user with only SELECT rights to some tables and USAGE rights on the schemas they're in should be fine.
There are some important caveats though. SECURITY DEFINER user defined functions can do anything the defining user can do so if you have SECURITY DEFINER user defined functions that weren't carefully written you might have opened security holes. The same is true of user-defined functions written in C - so consider your extensions carefully. Finally, you need to be extremely careful about any functions written in "untrusted" languages like plpython, plperl, etc (as opposed to plperlu which is sandboxed) as these must be implemented carefully to make sure the calling user can't trick them into doing things they weren't supposed to do.
If you plan to give a user direct access to write raw SQL you have to be more careful about securing your DB. Don't GRANT rights to public, and REVOKE them where they're granted by default. Check security definer functions to make sure they have a SET search_path option defined. Etc. It's generally safe, but only if you're careful.

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.

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.