Reputation: 261
I am developing a file management system with a PostgreSQL database back end. I am writing the client side using Qt library that will connect and query the database server.
The file management system by default restricts access to top-level directories to all users, unless a specific user has access to a specific top-level directory. Access can be given by anyone to anyone, as long as the user giving access already has access him/herself. This is accomplished by maintaining a table in the database with 2 foreign keys: userID_fk and directoryID_fk. If a record exists in this table with a particular user having access to a particular directory, than the directory is displayed on the user's screen. Otherwise, the directory is not visible to the user.
This design presents a challenge: The user is already able to connect to the database, and is a legitimate user as far as the database server is concerned, so it's easy for a user who does not have access to some directory to give themselves access by simply connecting to the database server not using my client application, and simply adding a record in the table with the directory id and their own user id. I cannot allow this, however.
What I want to achieve is giving all database users full access to the database server but only via my own client application and not outside of it.
I have thought of several approaches to solving this challenge but I am seeking your recommendations as to the best architecture to prevent users from accessing the database server outside of my client application.
Possible design approaches I thought of:
This design however, is cumbersome to the user - the user would have to provide a password to connect to my "server" and then a second password to connect to the database server. And in my particular case, the data on the database server is also encrypted, which means the user would have to provide a third password to access a database. This is a little much for an average user I think.
Beyond these 2 approaches, I have not been able to think of a better design. I would really appreciate your suggestions, including your thoughts on my proposed designs. Many thanks.
Upvotes: 1
Views: 164
Reputation: 52107
We had a very similar problem under MS SQL Server and solved it by providing an "API" at the level of stored procedures. Hopefully, you'll be able to do something similar under PostgreSQL.
The idea is to forbid all clients from querying the database directly. Instead, you only grant "execute" permission on the "public" stored procedures. "Private" procedures (i.e. implementation details) and tables are completely inaccessible to external clients.
Together, public and private procedures implement row-level security and any other business logic needed. Since all clients are "funneled" through this API, nobody can circumvent row-level security or any of the business rules. This includes any future applications that may be implemented to "talk" to the existing database.
In our case, we had 1:1 mapping between database users and our "application users", and simply let the DBMS authenticate users during log-in (which also has an added benefit of integrating with Active Directory, which was important in our case). Stored procedures would then use current database user name to implement row-level security.
You should also consider security caching. In our case, we have a very complex security mechanism that supports permission inheritance (from parent to child objects) and workflows, which makes it expensive to calculate - so we implemented a security cache that gets "lazily" updated and prevents repeated security calculations. The security cache is completely hidden behind stored procedures and transparent to clients. Depending on complexity of your security mechanism, you may consider whether some kind of security caching would be a good idea performance-wise...
Upvotes: 1
Reputation: 48256
I think you'd be better off using Postgres's built-in security system, instead of writing your own.
Each user gets their own username/password (or you could use SSL certs or Kerberos)
Postgres supports users and roles, and access control on tables, schemas etc, as well as column security.
Currently, you need to mimic row security with an "owner" column in a table, and views that prevent users from seeing rows they should not. You'll need to figure out "sharing", perhaps with an ACL array column (of allowed roles), or using a related table.
9.3 has security_barrier views, which prevent some snooping. in 9.4, they are updateable. 9.4 also supports WITH CHECK OPTION views, which would be useful here. 9.4 should be out later this week.
See http://veil.projects.pgfoundry.org/curdocs/main.html as well.
Basic example:
create schema data;
create table data.files (
file_id int primary key,
name text not null,
owner name not null default current_user, --use a trigger in real world
acl name[] null
);
create view files as
select
*
from data.files
where
owner = current_user
or acl && array[current_user]; --&& is array overlap operator
insert into data.files values (1, 'test', 'admin', '{CSLover}');
You'll need to add some other stuff obviously.
Upvotes: 0