Login system using physical postgres users not "logical" users - security

I'm currently building an application that has to conform with SOX auditing requirements. One of these, is that all inserts, updates and deletes (but delete you can ignore), need to leave a trail that is difficult, if not impossible for a standard user (or non-DBA) to change.
This means, I need to enforce the auditing at the database level via triggers on insert, update and delete.
My problem is; this is a webapp... The typical design pattern is to store users as "logical", for example; in a "users" table. What I need, is for the application to actually run as the logged in user after the initial login.
My thinking (which is likely not the best) is to do the following:
Load the login page via a standard username (webapp)
Check a table called "stored_users" for their logical username/password.
If they enter the correct user/pass; retrieve the db username, generate a session password (stored in KVSession on redis), update the user on the postgres DB and login with it.
After a defined time of inactivity, destroy the password session, reset the db password for the user and log them out.
Does this sound like a safe way to ensure the following?
My users are always using postgres users; so I can enforce the triggers via CURRENT_USER etc..
Security by always regenerating the postgres user password with a random, temporary password
I'd really like to hear what others have to say on this matter; as I really can't find this on Google (or I'm not searching the right terms). It seems the prevailing mindset for user logins is to store them as logical records and have a global connection user.

To achieve your goal
all inserts, updates and deletes, need to leave a trail that is
difficult, if not impossible for a standard user to change.
you can create:
1) Two schemas: one for common tables, one for security stuff like login/pass(hash) table, user session log, change log table, etc.
2) Two users: one common user, that can only use dml on common schema (no ddl), one superuser.
3) Login function that will check provided user/pass against login/pass table and log successful/failed attempts into user session log (you need SECURITY DEFINER function)
4) Set of audit triggers on common schema tables that will check the user privileges and log any changes, made by the user (SECURITY DEFINER functions here too).

Related

Caching user permissions in redis, good idea?

For last few days I am working on improving app performance. What do you think about caching user data and permission in redis? In my case every time when user create post or try to upload file app check in database, if user exist and fetch user permission and role. My first idea was to put permission and user role in session but user can have multiple session on different device, so every time when user get ban or user permission change app need to update every user's session and as far as I know express-session do not support this kind of feature.
Unfortunately it's a very open question with no strict answer. But as an advice, I'd say Redis is perfect for storing user session altogether. Moving parts of the session would still require you to query the database (you get the session, you must query for user information, and also ping Redis for permissions & roles). So I think you should put all session data in one place, and the fastest would be Redis. It would also let you save that data so it's not entirely in the memory. There are also many ways to optimize it, like when to write the data (like every second) and so forth.
Querying Redis is extremely fast and efficient since you don't have any user to user relations, and most of the times you won't search on anything different than "get me that user session by id".
It's a very standard solution to put user session in Redis, if not the most often used one :) Good luck!

Web user is not authorized to access a database despite having Editor access in the ACL

In my XPages application, web users can perform a self-registration. In the registration process, a user document for the web user is created in the address book and the user is added to a group that has Editor access for the database. After executing show nlcache reset on the Domino server, the user can login to and access the application.
In ~98% of all registrations this works perfectly fine. However, sometimes new users cannot enter the application after the login because, according to the Domino server, they "are not authorized to access" the database. The login must have worked because the user id is correct. The exact same user id can also be found in the Members field of the group that has Editor access to the database. To additionally verify the user's access level, I executed NotesDatabase.queryAccess() with the user's id. It returned 0, which is the ACL default and means "No Access". Yet, there are dozens of users in the same ACL group which have absolutely no problem with accessing the database.
At the moment, we "circumvent" this problem by manually removing the user's document from the address book as well as remove him/her from the Members of the ACL group. Afterwards we ask the user the re-do the self-registration with the exact same information as before. Up to now, this second registration has always worked and the user can access the application. Yet, this is not a real solution, which is why I have to ask if anyone knows what could be the problem?
Don't create entries in the address book directly. Use the adminp process for registration. To minimize perceived delay send a validation/confirmation message the user has to click.
Comment of 12/02/2015 seems to be the correct Answer:
Check if the self-registrated user has TWO consecutives spaces in his name, (could be because trailling space too)
In group domino do a FullTrim. So we have
John<space><space>Smith
that is not in group XXX because in the members it's:
John<space>Smith.
This may have something to do with the frequency at which the views index are refreshed in the names.nsf
Since the access control is done groups in the ACL, the server will "know" which user belongs to which group only after the views index have been updated.
In a normal setting, this can take a couple of minutes.
You can test this hypothesis by forcing an index refresh, either with CTRL-MAJ-F9 from your Notes client (warning, can take very long depending on network and number of entries in the names.nsf) or with the command
load updall -v names.nsf
... or by having the users wait a little while and try again 5min later.
Ok, first a question. If you let the user wait a couple of minutes will the access then work? I.e. is it a refresh/caching problem - or an inconsistency in the way you add the user to the group?
I assume that the format of the user name is correct as it works in most cases (i.e. fully hierarchical name)... Is there anything "special" about the names that do not work?
I do a similar thing (and has done several times) - although with some differences :-)
I typically use Directory Assistance to include my database with a "($Users)" view. When I update anything in this view I do a view.refresh() on the view (using Java). I typically do not use groups in these type of applications (either not applicable - or I use OU's or roles for specific users). I am not sure how the group membership is calculated - but I guess you could try to locate the relevant view (though none of them seemed obvious when I looked) - and do a refresh on it.
/John

Should I validate access permissions each request?

I've always wondered whether it's better to check the database for account access permissions every single request, or cache (say, an ACL) in the session state.
My current case isn't particularly mission-critical, but I feel it would be annoying to have to logout and log back in to refresh cached credentials. I've also considered using a temporary data store, with a TTL. Seems like it might be the best of both.
Security wise, it is better to check the DB every time for permissions. The security vulnerability comes in that if the user's permission are reduced after the session is created, they could potentially still be achieving a higher level of access than they should.
There are a few things you can do to stay secure without performing a full query, provided you're early enough in the development cycle. If you have role-based access control (RBAC), you can store a fast lookup table that contains a user's role. If the user's role changes during the session, you mark the permissions "dirty" in the lookup table, causing a querying of the DB for the new role. As long as the user's role stays the same, there's no need to query the DB. The lookup table then, is basically just a flag that you can set on the backend if the user's role changes. This same technique can be used even with individual access controls, provided the granularity is not too fine. If it is, it starts to become a bloat on your server. We use this technique at work to speed up transactions.
If you are late in the development cycle or if you value simplicity more than performance (simple is usually more secure), then I would query the DB every time unless the load gets too heavy for the DB.

Symfony 2 - how to disable querying user at every page load?

I'm using my own User class as and entity provider for security system in symfony 2.0.
I noticed that on each reload of the page symfony is fetching user from db:
SELECT t0.id AS id1, t0.username AS username2, t0.salt AS salt3,
t0.password AS password4, t0.email AS email5, t0.is_active AS
is_active6, t0.credentials AS credentials7 FROM w9_users t0 WHERE
t0.id = ? Parameters: ['23'] Time: 4.43 ms
Is there any easy way to disable this behaviour? Maybe serialize user data in session variables or cache them some way?
You can change this behavior in the refreshUser method of your UserProvider.
You should be careful when doing this with doctrine: There is an issue at FosUserBundle github, explaining the pitfalls:
Storing it in the session would lead to several issues, which is why it is not done by default:
if an admin change the permissions of a user, the changes will have an effect only the next time you retrieve the user from the database. So caching the user must be done carefully to avoid security issues
if you simply reuse the user which was serialized in the session, it will not be managed by Doctrine anymore. This means that as soon as you want to modify the user or to use the user in a relation, you will have to merge it back into the UnitOfWork (which will return a different object than the one used by the firewall). Merging will trigger a DB query too. And requiring such logic will break some of the built-in controller which are expecting to be able to use the user object for updates.

CouchDB - Figuring out database security

CouchDB offers validation prior to allowing an object/row to be inserted into the database. This make sure that if you have a public facing couch application, you're database won't be filled with junk by just anyone.
User <-> CouchDB
However, I'm tring to figure out what that looks like comming from the standard application design process where you have a trusted middle layer that does much of the auth work. For example, most apps place Ruby or PHP between the database and user agent which allows the application to figure out information about the user agent before allowing something like a post to be saved to the database.
User -> Ruby -> MySQL
User <- Ruby <- MySQL
How do you trust the user to do administrative tasks when the user can't be trusted?
For example, how would you do something like "email verification" prior to inserting a user row using just couchDB? You can't let the user agent insert the row - because they would fill the system with spam accounts. On the other hand, there is no middle layer either that can insert the row after they click the link in the email.
How about this, I would assume that you would allow anyone to enter their email by creating a new record in a public table like email_verify. This is something that a public user agent could do as the table would not do anything in the application - it would just be a holding tank.
Then node.js could track the _changes feed and send an activation email while creating a new entry in a private table (like email_confirm) (node.js would serve as a trusted middle layer). If the user clicks that link and comes back then... [unknown] ... and node.js could finally create a record in the private user table (user).
At this point we could then rely on couchdb validation for the rest of the application since we got a confirmed user account created.
As more background lets imagine a discussion built on couchdb that anyone can register for. We don't want to allow just anyone to directly submit content without some kind of verification - yet the user agents all directly run the system. (Tables would be Thread, Comment, & User). How would this work?
I would think about adding roles to existing users in this issue.
Using couchdb's validation and changing _design/_auth can be a good idea to add email, email_verified and randomly generated email_verification_code in _users database when the user firsts registers.
To send mail, get confirmation, resend confirmation you can use external processes. (for an example usage of external process you can check couchdb-lucene).
And at last you can again do a quick check in _design/_auth in user update process if verification code matches and add verified_user role for that user.
This way all your requests would pass over couchdb, you would use external process only when you need to send mail and get confirmation.
Edit : Forgot to add (since it was pretty obvious), I would add verified_user role to database readers.
Couldn't you just make use of CouchDb's Validation ?
Users could be flagged. Upon registration, a User is added to the Users database. He gets his mail and then is flagged "valid:true" or something like this upon answering to that mail or clicking a link.
With validation users could not only be "logged in/out" but also access authorization can be implemented with more granular access rights. E.g.: Only mark threads solved if one is the author, admin, whatever...
Or does this seem impracticable?
After talking with some people on #couchdb IRC, it seems that they can't figure out out a way to do something administrative (like activation users that click on a email link) with out using a "backend" process like a node.js server which keeps track of the _changes feed.
I was hoping for a pure couchdb app - but it seems like couchdb still has a little ways to go.
Still, the good news is that you can hand off 80% of your applications logic/processing to your users. The other 20% will be 1) a node.js instance for things like sending emails or checking recaptcha and 2) record validation functions running in your couchdb, and 3) map/reduce (query) functions. These three things cannot be offloaded to something "untrusted" like a user-agent.

Resources