PHP MySQL Row level security - mysql

I am looking for an example or information on row level security for PHP and MySQL. I have done the basic google reasearch, I have read all the posts / articles about using views and adding fields to table to specify what user has the right to view the object. Those example are fairly simple and would require lots of configuration / maintenance.
Here are a few real life examples of what i am looking for:
Clients data, allow to configurer what user or user group can view all or parts of the client file. This must be persistent for all the application features including reports and dashboards.
Employee files, give access to immediate supervisor and HR to an employee file without having to reconfigurer the access rights when supervisors change.
I think this should be handled directly from the database layer, but could also be applied to other resources for examples, uploaded documents.
I'm hinting to some sort of "filter" that I could pass my data into so it could be filtered.
Any interesting links to articles or frameworks that have implemented this with success would be greatly appreciated.
Thanks.

You would need to use MariaDB to do this, as MySQL doesn't do ROLEs, though you might be able to use GRANT PROXY to accomplish what you want in MySQL.
I think that different "tenants", i.e. paying customers, should be in different databases to avoid leakage. You can use scripting to automate this.
But if you want intra-company row-level security, you can accomplish this with an extra column per table and some views and triggers.
create a table with an owner column. Use an insert trigger to set owner to the current user. REVOKE all privileges on the table.
create a view WITH CHECK OPTION on that table that checks that current user is in a role that matches the owner. GRANT all privileges on the view.
Example:
create user `pointyHead`;
create user `dilbert`;
create role `manager`;
create role `minion`;
grant manager to pointyHead;
grant minion to dilbert;
grant minion to manager;
Not sure if there is a function to check if user is in role, but you can always use information_schema.applicable_roles.
You can use column-level grants to give different column permissions to different users. http://dev.mysql.com/doc/refman/5.5/en/grant.html#grant-column-privileges .

Related

Designing a SaaS on a single database, multi-tenant (SQL)

I'm working on a SaaS product and trying to figure out the best way to design the database for my scenario, which I think is pretty standard.
I should not that I don't have an experience designing such a database.
I tired researched online, but there isn't really any info I could find about implementation. There are quite a few comparing the different multi-tenant architectures.
For the multi-tenant approach, I decided go with a single database - seemed to be the most fitting.
Here's the basic list of what should be supported:
Multiple clients, all separated, no sharing of data between them.
Each client has it's own user base (staff/employees).
The client's staff members have different access levels to the system (exposure to different areas, ability to perform certain actions)
Each client have it's own customers.
I can wrap my head around the basic concept of having the tenant_id on any table belongs to that tenant. I guess my issue is more with how to combine it with different access levels per client's staff member.
How would you go about it?
Any reference some implementation of such a DB?
Thanks
Update
After #dmfy answer, I gave it some thought and came up with this solution:
account
-id
-name
user
-id
-account_id
-username
-password
role
-id
-account_id
-name
user_role
-user_id
-role_id
access
-id
-role_id
-name
role_access
-role_id
-access_id
session
-account_id
-user_id
-token
I'll explain-
The role table is essentially a "group" of users associated with a list of permissions/access levels.
The access table represents a single permission. An area of the platform, an action that can (or cannot) be performed.
A row in the session table is created after a successful login. Each time there's a call to the server, if the user has been verified against the token, I will lookup the roles for that user (using the session.user_id on the user_roles and collect it's access list using role.id on role_access.role_id).
Once I have the access list I can check against the request and see if the user is permitted to perform the action.
Notes
role can be customized for each tenant/account (e.g one can have "Management" and "Employees" and another can have "Management", "Support", and "Sales" ), hence the association with account.
access on the other hand, is platform-wide. The platform have the same set of areas and actions across all tenants. So there is not need to associate it with a specific account.
An improvement to the access lookup could be to store the access list on the session on login, to eliminate the double join (get all the user's roles, get all the roles' access lists).
Questions
Firstly, what is your overall opinion on the design. Do you see any flaws?
Is saving the account_id on the session really needed/a good idea?
Is having the server check whether the user has access to a certain resource is the standard way of doing this? Is there a way to do this as part of the itself query (e.g get an error from the DB itself)?
You might get a better answer by describing the requirements before you outline the solution.
Your design seems to describe an authorisation scheme. It looks fairly credible - I'd summarize it in natural language as:
A tenant is an account.
An account has many users.
A user can have
many roles.
Roles grant access to many permissions.
The system
maintains a list of sessions, mapping requests to users; this in turn
allows the system to check whether the user has permissions for a
given action.
Without knowing your requirements, that seems fairly reasonable. You may want to include a link from "account" to something your application recognizes as "tenant".
The big question is how you will use this data in your application. Checking permissions - especially fine-grained permissions - for each request could be expensive.
The specific solution here depends heavily on your application framework - many have built-in authentication/authorization models, and it's usually a good idea to use those built-in features.
For ideas on how to implement this, you could look at CanCanCan, an authorization framework for Ruby on Rails, or Authority for Laravel.
It's also not clear how the actual data in your system will be linked to an account - if your system tracks widgets, does the "widgets" table have an "account_id" column? If so, how does your application track who is and is not allowed to access that row?
It sounds like you're conflating database users with application users. In a SaaS product with a shared-schema model, individual users won't have direct acess to the database; instead, your application connects as a single user with appropriate rights on all objects it needs. What you're worried about is what areas of the application users can access and what actions they can take. This means you need to build your authorization model into your schema.
The simplest possible model has two levels of access: regular users and administrators. This can be represented with a users table having a tenant_id to associate individual logins with the correct client, and an is_admin flag. Your application then ensures that only users with the flag set can access administrative functionality. If your authorization model is more complex, design your schema appropriately (users may have a many:many relationship with roles, for example).
Note also that a tenant_id column is only strictly required for tables directly related to tenants; if you have a profiles table with a user_id, you can trace the relationship back to the tenant through users. In some cases it may make sense to add the tenant_id to avoid long join chains.

mysql phpmyadmin Permissions USAGE

I want to create a user that will have only read permissions
That it will be able to run SELECT queries but will not be able to run UPDATE,INSERT... or modify the DB.
I read that USAGE means - no permissions, what can it do?
Will a user with USAGE permissions be able to modify the DB?
In phpMyadmin you set priviliges according to your wishes. This meaning:
If you only wan't the user to be able to run SELECT queries, Thats what you select. The user will then not beable to edit your data in any way.
Hope this helps.
The best way to learn the capabilities of an account is to test it, try to create a test table and log in with that user, try also to execute the writing commands on it and you'll see by yourself if he can write or not.
https://dev.mysql.com/doc/refman/5.1/en/privileges-provided.html#priv_usage
The USAGE privilege specifier stands for “no privileges.” It is used at the global level with GRANT to modify account attributes such as resource limits or SSL characteristics without affecting existing account privileges.
So no, a user with only USAGE will not be able to see or create other databases. They can connect, see information_schema, get STATUS, and very little else.
Anyway, you've mentioned phpMyAdmin which doesn't provide USAGE as a checkbox in the permissions area; creating a user with no other options selected gives USAGE privileges here. Select anything further you wish to allow from the checkboxes provided.

How to define super user concept in MySQL DB for web application

I am developing the application in which i have a super user concept. Super user is the user who has all the access for the application. So what my initial thinking is in user table the user with id 1 will be my super user. but how safe is this in terms of security concern ? is there any other logic which i can use to define super user ?
I have done more emphasis in coding side. I also implemented the roles and other access permissions, But what i need to to do is something like ghost user. Whenever he logged in he could be able to access everything like he is a father of application. for his access i shouldn't need to check any role conditions or access condition. is it possible ?
Thanks.
Why not work with roles? Make a column in your user table where you have 'SuperUser', 'Admin', 'ReadOnly',... Or perhaps just 0, 1, 2... and match it with a constant/enumerable in your code. Now you can easily change your super user, make multiple super users, give someone temporary super user rights, define other roles...
From the database point of view it is valid to define two or more users and grant more or less permissions to them, work with roles etc.. But as you said - it's about the application. So in parallel to the database security you need to consider application security in terms of:
which user may get which functions, menu items, web pages etc.
how can this be configured and parameterized, etc.
I personally put a bit more emphasis on the application side and less on the DB side. So thinking of e.g. PHP + MySQL, I have 2 DB users (operator, admin), but a database table within my application for each (application) user, assigning to them the operator or admin login for the DB and defining which parts of the application they get.
As a complement to the other answers:
Don't forget you could create users and grant/revoke permissions at DB level. I would not push for a 1-1 mapping between your application users and the DB users, but you could use that to implement "roles" and enforce permissions at DB level as an extra level of protection. This might be especially interesting if you have some users with "read-only" and/or "anonymous" access. This would prevent "escalation of privilege" due to a bug in you application code.
Super user is the user who has all the access for the application. So
what my initial thinking is in user table the user with id 1 will be
my super user.
In the Unix tradition, super-user is generally ID 0. This might improve code (maybe) and more important make it more understandable by programmers familiar with kernel/security coding.
But what i need to to do is something like ghost user [...] for his
access i shouldn't need to check any role conditions or access
condition. is it possible ?
I don't think this is a good idea to somehow "deactivate" all your security checks for one particular user. In order to improve maintainability and not clutter the code with permission-checking, as of myself, I would encapsulate all the code that need to check permissions in wrapper functions or objects, then I would use that wrapper in the rest of the application. Based on that, and if you implement "roles" at application level as someone else suggested, handling the "ghost user" shouldn't be too much of an issue.

Good security in MySQL web application: Root? Not Root?

Suppose you're writing a simple database web application using Ruby and MySQL. Access to the database is controlled by Ruby code. The user name that the Ruby code uses to access the data is the only regular user on the database. Does it make sense for that user to be "root"? Or is there any extra security in creating a second user just for the application?
Simple, consider the root as the main user, who can do everything (by default).
If he wants to dump the whole database, he can, if he wants to create some data to create (for example) fake account to overpass your bank system, he can.
So if your code is not enough secure (and this is quite often usually), you have strong security issue.
Usually, "a basic" security (really basic), should looks like that :
create a simple user, give him (with GRANTS) the right to SELECT, INSERT, UPDATE and DELETE on a specific database.
create another user who can SELECT and lock tables and SHOW VIEWS to perform dump (database save).
On a more "complex" system, you should create many users, depending of what they should access, this is for simple reason : if somebody got a SQL injection access, if the user can only access to a single view (for example), and not the whole database, this is a security issue but not the baddest one...
Also view are often used for that...
And finally don't forget triggers if you want (for example a log table), to disable insert or update or delete on a table, for everybody (except somebody who can destroy trigger of course) :
Use a trigger to stop an insert or update
Besides editing or deleting all data in your database, the root user also have the FILE privilege which gives access to:
LOAD DATA INFILE which can be used to read any file on the server machine.
LOAD DATA LOCAL INFILE which can read files on the client machine (the web server machine).
SELECT ... INTO OUTFILE which can create files on the server machine.
This is why your application should have only the privileges it needs, and this is also the reason your MySQL server daemon should be run as a non-privileged user on the server machine.
See also General Security Issues in the manual.
If everybody/thing is root, you lose auditability, you lose the ability to restrict the app to stop attacks (i.e. your app doesn't need this segment of sensitive information, seal it away from its user). If somebody compromises the app, you can suspend the account etc.
I would not make a user "root".
I'd create a separate username and password just for that application and GRANT it only the permissions required to do its job.
I would create a new user, giving it only the permissions it needs (SELECT, UPDATE, INSERT and DELETE usually do the trick). Like that, you limit the ability for the code to be manipulated in an unintended way.
"root", or generally speaking, users with Super User privileges, can change passwords, delete accounts, and therefore prevent you from accessing your own database.
If you server hosts only one application, then you may not need to create several lesser privileged accounts. However, it is common practice to create at least one user for each application, so that if one application gets compromised, other applications (and underlying data) may not be.

MYSQL Security questions regarding ROOT user

The datasource used by my web application connects using the ROOT user. The ROOT user has all privileges assigned.
My concerns are:
1) Should I be using this user (and is it ok / secure) or should I create another user with a more restricted set of rights
2) If I do use another user, how do I cater for all my procs that begin with:
CREATE DEFINER=`root`#`%` PROCEDURE `Blah`()
3) Is it a bad idea removing privileges from the ROOT user. For example, if I remove the "DROP" privilege, will I still be able to DROP objects when logging in via the Admin or Query Browser. MY guess would be no and that I shouldn't mess with the privileges.
Any documentation / links / info regarding this would be appreciated. Thanks
You should absolutely use a restricted user to access the database as much as possible.
There are privileges that allow your users to access procedures. I'm not that familiar with it but here's the official documentation: http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html
Don't mess with root's privileges :)
No, your application should not connect using the root user. You should create and configure a user that has the permissions required by the application and no more.
I usually go with at least three users:
Root can do everything; changing root's permissions is a recipe for disaster (unless you know exactly what you are doing)
The application has its own user, and this user has very restrictive permissions - usually just SELECT, UPDATE, INSERT, DELETE on the tables it needs. In any case, no permissions that would allow schema modifications (CREATE / ALTER TABLE and such).
A special user which can access the application's database, but nothing else. This user is used for maintenance tasks such as schema upgrades, but not for the application itself.
It's a bad idea to use the root user for any task. You can see it like the system-user: only the system should use it, when it needs it, to do everything.
Create a new user and give it only access and priviledges to do what it should do. This is called the principle of least privilege.
In this case, procedures are part of what a certain user, module or part of a program should do in normal circumstances. Hence, the user you create owns (DEFINER) that procedure. You should remove the procedure from the root user and add it to your newly created user. If it's impossible to remove from the root user: then so be it! However:
If a user want to access the procedure, give (GRANT) them access to it. In the case the root user still owns the procedure, any other user still can be granted to use the procedure.
The root user is, as I already mentioned, the system user. If you drop priviledges then any program or user using the root can't do what is expected (being the system-user capable of doing everything), and this cripples your system.
Think about this: how would you add a new database, if you dropped the "ADD DATABASE" privilege from the root user?