Providing MySQL users with just the minimum privileges - mysql

For a web application, when creating the user which will connect to the MySQL database, you have the choice of privileges. Assuming that the only actions intended to be done by that user are SELECT/INSERT/UPDATE/DELETE, it seems to make sense to only provide those privileges, however I've never seen that recommended anywhere - what are the reasons for and against this method?

I disagree with Bill here and Atomix's line of thinking is more suitable. Unless it can be demonstrated otherwise, Bill's answer highly increases the risk of the database being compromised.
Perhaps for very experienced developers there is other security in place, but for other developers giving a script full, unfettered access to do ~anything~ to a database is asking for trouble, when there is no need to.
The principle of least privilege should be in use here. For MySQL, have a super user with all privileges which is used for creating tables, drop database, and so on. Ideally this username and password is never seen in any PHP file or any file on the web server. (I'm using PHP as an example but it applies to other web applications). You would only use this username and password with something like PHPMyAdmin or MySQL Workbench.
Then, for PHP scripts, have one with the minimum required, such as just INSERT, SELECT, UPDATE, maybe not even DELETE, depending on your PHP script. This would be in the PHP files, that is, actually only ONE file OUTSIDE of the document root, as is recommended by most.
The reason is thus: yes, you do not need a MySQL user for every web application user. But principle of least privilege ( http://en.wikipedia.org/wiki/Principle_of_least_privilege ) should apply. If somehow your MySQL super user is compromised because you accidentally named your MySQL connect script as .txt instead of .php, or someone gained access to the web server files, at least the "worst" they can do is SELECT, UPDATE and INSERT... Which while can cause big problems anyway, is not as bad as giving them DROP DATABASE, DROP TABLES and much worse things.
Additionally, in my current project due to agile development practices (I do not work for but recommend http://www.agilealliance.org/), one or two "non-tech" team members are directly using PHPMyAdmin to make direct changes to the MySQL database. This is because creating a CMS for simple direct data entry is not required. In this case, a third MySQL user with reasonable but again, "just enough" privileges is suitable for them. We don't want to cripple the team member with too little privileges, but of course they shouldn't be able to accidentally delete or change things.
Since MySQL doesn't have ROLES (as of the time the original question was asked, and as per Bill) then allowing any web script to just access MySQL with only one Super User is very risky.

There are other privileges that a user might need during an ordinary application, for example:
CREATE TEMPORARY TABLE
EXECUTE (stored procedures)
FILE (for SELECT INTO and LOAD DATA)
LOCK TABLES
There's also the possibility that minimal privileges could mean only SELECT on certain tables, and only SELECT and UPDATE on other tables, etc. This is subject to change any time the application's functionality is enhanced. And there are weird cases, like the need to have SELECT privilege on a table you never query, because it's referenced by the foreign keys in a table you UPDATE. So tracking minimal privileges is a royal pain.
What are you trying to restrict by using SQL privileges? You're the one who wrote all the code, so managing SQL privileges at a fine granularity shouldn't be necessary. Frankly, if your users are able to upload and run SQL statements that you haven't vetted, you have bigger problems:
SELECT * FROM mytable, mytable, mytable, mytable, mytable ORDER BY 1;
The real tasks you want to govern aren't at the database level, they're at the application business level. For example, a CMS has operations like create a page, edit a page, administer comments, etc. These tasks are higher-level than SQL privileges. You could mimic them with SQL roles (which are groups of privileges), but SQL roles aren't widely supported.
I don't know anyone who maps their application users to distinct MySQL users. They're users you authenticate in your application, after the app has connected to the database (the users are just rows of data in the database).
So you're probably better off having your web app use a single MySQL user with full privileges.

A web app usually uses just one user to access the DB, rather than a user per actual user account. Applying minimal privileges is good practice. The username and password is going to be coded into your script (does anyone obfuscate this?) so there's room for compromise if your scripts aren't managed properly.
In my experience, I very, very rarely have the app delete rows - much better to flag a row as deleted as you then have an audit of what is there rather than not knowing what was there! This approach also helps keep tables and indexes optimised.
Therefore, I would suggest allowing only INSERT, UPDATE and SELECT - it will quickly become apparent if parts of your app need to be relaxed a bit!
Allowing more privileges can only broaden the possibility for DoS attacks by issuing resource intensive commands, or allowing malicious data attacks.

Related

Is there a system role to allow viewing definition of all objects in a database?

I need to request that a global group by given sufficient access to a production database in order to perform support of applications that use the database. I am trying to identify what specific rights I need to request.
in order to perform a query against all of the tables, I would like to request db_datareader access. i'd like to avoid the maintenance of making sure that the global group has SELECT and VIEW DEF access to all objects. I know that db_datareader rights, if approved, will give a user full SELECT rights to all tables. Is there a counterpart Role that grants rights to view teh definition of all tables, stored procedure, views, etc?
USE [your database]
EXEC sp_addrolemember 'db_datareader', '[your user name]'
Define "sufficient access to a production database"
As a DBA, I would not give any DDL admin or any type of access that allows users to alter schema on the fly, that's a recipe for a disaster and will make your DBA work harder. A DBA must and should be able to help on performance issue and change production schemas after proper testing. You really do not want to change production schema without testing 1st.
Having said that, if user(s) want limited access to troubleshoot performance issues (this actually can make your life easier) they may need any of these:
VIEW DATABASE STATE
VIEW SERVER STATE
Those two, allow access to DMVs, which are useful to pinpoint performance issues and how queries are running.
SELECT, UPDATE, INSERT, etc, are normal though. If your database objects (tables, views, sprocs) do not require granular permissions, I would use any of the default database role and put the user or users inside.
Permissions to run store procedures would be EXECUTE.

One-off Read-only SQL Statement Verification in MySQL 5.5?

I have an interface that I want to allow an arbitrary SQL select statement (as an input string) to be input that will select data from a given table for use in an operation. I want to make sure that this statement does not make changes to the database.
string query = GetStringFromForm(...);
DatabaseStatement statement(query);
statement.execute();
while (statement.fetch(...))
...
One way to implement this would be to create a new database user with the appropriate permissions and then execute the statement under that user. This would be a hassle as it would require setting up this new user and creating a new database connection for it and so on.
Is there a way to isolate the permissions for a single statement MySQL 5.5? Or some other way to do this?
With MySQL 5.6 you can do:
START TRANSACTION READ ONLY;
https://dev.mysql.com/doc/refman/5.6/en/commit.html
I think it's what you're looking for, but you have to upgrade to 5.6 to use it.
Don't connect to the database with the same login for everything.
At the very least you should use thee logins for this achitecture:
A development level login for creating tables, etc
The login used by your application to make the application run
The login used to execute user specified queries
This means that your application login only has the permissions it needs - to read or write to the tables necessary, not to do everything to every table; application logins shouldn't need to be able to CREATE or DROP tables, for example.
This limits the impact of mistakes in code, but also the scope to which someone could hack your system (such as with SQL Injection attacks).
It also means that the login for running user specific queries needs only to be granted SELECT permissions, and only to the tables/views/function that it should be able to use. If they try to run an INSERT or a DELETE that they don't have permissions for, you can catch the error and tell the user that they're a very naughty boy - secure in the mind the the RDBMS simply won't let the user damage anything that you haven't already given them permission to do.
In short, RDBMS already have login permission architectures. Use those to limit the permissions and functionallity of different aspects of your code.
I would not try to re-invent this wheel. It is extremely likely that there is a trick or hack that you missed that exposes a vulnerability in your application. I appreciate that you say this is a hassle, but it really is the right way of doing things, and the only reliable way of doing things. There's a reason that it's the standard approach to data security, sorry.
(And trust me, even if no-one is trying to hack your system, eventually someone will type some screwball query in - accidentally bypassing your security and making a pigs ear of your database.)

MySQL: Create a user for reading and another for writing?

I have been searching for this for a while and unable to find something useful.
Is it a good practice or even important to create 2 MySQL users, one for reading and then use that whenever I'm initiating a MySQL SELECT.
And on the other side, create another user for writing and use it whenever I'm doing an INSERT, UPDATE, DELETE, ...?
Would this help at anything for example if I'm writing and reading to the database at the same time?
Assume we're using InnoDB tables.
"good practice" is very hard to define - you've got a whole bunch of different things to trade off against each other.
I'm assuming that the database is being used as a back-end for some other system, and that your users don't have direct access to a SQL prompt. In that case, there are no real benefits to creating different MySQL users - it simply makes the front-end more complex, and an attacker who can reach the database and knows the "read-only" credentials almost certainly also knows the "read/write" credentials. From a security point of view, you should invest your time in network security of the database server, and secure storage of connection details.
From a concurrency point of view - two or more users reading and writing at the same time - you won't really gain anything either. This particular requirement is one of the things relational databases do very well, and I don't think it's affected at all by the permissions of the users - it's far more to do with whether you're using transactions, and how quickly your SQL executes.

Should each user get his own database user/password when they use a single app?

What I am trying to ask is ...
Users will only ever access the database via my application. The application itself allows an admin user to create/modify/delete users and give them certain privileges. So, I have a table which contains each users log-in name & password.
I am still developing the app, so it currently logs in as root with no password. Obviously, I will change that, but what's the best practise? Should I have a single database user & password which the application uses, or should I create a separate user for the databaase each time a user for the application is created (or modified)? The latter seems like more work.
Your APPLICATION should certainly have separate user ids and passwords for each user. Given that, there's no reason for the application to have multiple user ids when it talks to the database. As long as the application's security is implemented correctly, there's no gain from having multiple DB user ids.
Giving each user his own DB user id would surely be a gigantic pain because it would likely involve all sorts of special cases and exceptions. For example, to log in to your application, the application would have to validate the user's id and password. How will it do that if the user doesn't have access to the password table? But if anything needs to be protected from unauthorized access, it's the password table. So you'd have to use one userid to do the login, then take that away and give a different userid. It's likely that there are other tables that a given user might be allowed to access in one context but not in another. The accounting department likely needs to see total amounts paid in salaries for the year, but maybe they can't see individual employee's salaries. Employees may be able to access data about their own benefit, but not that of other employees. Etc.
The only exception I can think of to this would be if you allowed some sort of generic access to the database. To take the most extreme case, if you had a screen where the user can type in an arbitrary SQL query which you would then execute. In that case, you could theoretically have the application analyze the query and attempt to apply security rules, but that would require your application to embed an awful lot of knowledge about SQL. In that case you'd be better to give each user his own DB user id and putting the security rules into the database engine.
Short Answer: Before the internet, yes. After the internet: nobody does it, but it is still perfectly acceptable.
Common practice in the internet age is to consider your application to be the user, and to give that application a login. The only actual benefit is some performance boost from connection pooling. The perceived but illusory benefit is security.
Understanding the security angle requires the realization that all security in the end resolves down to who can read and write from what tables, rows and columns. To see how this works, consider a user who is authorized to manipulate a highly secure table, and another user who cannot even see that table. The less privileged user successfully manages a SQL injection attack attempting to wipe out the secure table, it fails because the Database prevents access by that user to that table.
The takeaway is that there is no technical reason to use a single login except if connection pooling is important. Databases are very poorly understood by many internet age programmers so explaining how to use their built-in security is an uphill battle against many pre-conceived and incorrect ideas.
There's no reason to create a database login for each user. It's really your app that's interacting with the database, not the user. Creating extra logins just makes your database that much less secure.

CRUD Admins: Why not use MySQL users for auth/acl instead of User/Group tables?

In several frameworks (symfony/Django), you have admin generators that usually control access via a User table (which assigns a user to a specified Group table).
I'm curious, why not simply use MySQL's actual users (with select/read/write access already baked in) instead?
Another good reason that hasn't been listed is the fact that MySQL usernames/passwords are stored in clear text in config files. There maybe a vulnerability in your code that allows a user to read a text file, which then would give immediate access to a hacker without having to breaking a password hash. Having a your database remotely accessible is a serious secuirty hazard and is prohibited by PCI-DSS.
Another good reason is that in order to add new accounts or change your password your web application would need ROOT access, which is among the worst things you could do. In many databases (including mysql) this makes it very easy for a hacker to turn a sql injection vulnerability into full remote code execution (like uploading a .php file).
I would presume one reason would be, that many ISPs provide you with only one user account (without extra cost) to your mysql database, and thus, such an aproach wouldn't work as everyone would have identical priviledges.
The magic here being lowest common denominator and easy deployment as far and wide as possible, with minimum requirement in server administration.
I'd imagine most people are a little leery giving their application's MySQL user the ability to create and grant privileges to new MySQL users, particularly in a shared hosting environment. It's not that difficult to handle, it keeps everything within one database table, and you can have any permission you like.