MySQL Read-Only column based - mysql

I want to lock some fields/columns in a MySQL-Database, is this somehow possible?
Backgorund: We are using Revive also known as OpenX (of course the latest version) but it get hacked all the time. Especially the fields prepend and append in the ox_zone table.
What we already did to secure the system:
The Adserver is on a different Server
The Backend is not at the default location anymore
The Backend is secured by an .htaccess and .htpasswd
We removed all install files
We check the Core-Files every minute with the remote Git-Repo to ensure that we dont have compromised files (unauthorized file changes)
We removed the file: adxmlrpc.php Because its known as entry point for attackers
And some nice other tricks which I dont remember now...
But still sometimes the columns prepend and append are compromised, so I thought it would be great if we could lock these fields or set them to read only.
But I am of course up for any other solution.

You can set privileges on the column-level (and therefore only grant SELECT and INSERT) to the user that needs to be on read-only :
GRANT SELECT (column), INSERT (column) ON table TO user;
By replacing column, table and user with the appropriate values. GRANT documentation
You also need to be sure not to grant higher levels (table, data or global) privileges otherwise it would override the table-level privilege.
Best,

Related

Is it possible to make certain data available to certain users on a public mysql database?

Let's say we have a public DNA database running on mysql. Database contains only complete data. In this scenario, some special users want to add experimental data to the database, which may not be complete or they don't want it to be visible to everyone. Instead they want the experimental data to only be visible to users with correct privileges. What approach would you take to achieve this?
Presumably these datasets are large, and performance is important. That means the privilege system should be as coarse as possible.
If I were doing this, I'd create a "public" database, and use the MySQL GRANT command to allow guest users to SELECT on that database.
For example:
CREATE USER 'guest'#'%' IDENTIFIED BY 'changethispassword';
GRANT SELECT ON public.* TO 'guest'#'%';
Then, for the nonpublic datasets, I'd put them into other databases, and be more selective about the users GRANTed privileges. For example, these GRANTs give two different users access to private information and the public information.
CREATE USER 'venter'#'%' IDENTIFIED BY 'changethispassword';
GRANT SELECT ON public.* TO 'venter'#'%';
GRANT SELECT ON celera.* TO 'venter'#'%';
CREATE USER 'collins'#'%' IDENTIFIED BY 'changethispassword';
GRANT SELECT ON public.* TO 'collins'#'%';
GRANT SELECT ON hgp.* TO 'collins'#'%';
A user who has SELECT privileges on, let us say, the public database and the celera database, can issue queries like this allowing seamless (if not optimally performing) merging of private and public data.
SELECT whatever
FROM public.AGCT
UNION ALL
SELECT whatever
FROM celera.AGCT
Of course, it has to make scientific sense to take the union of these datasets. That may or may not be the case.
Don't be alarmed at the idea of creating multiple databases. They really are nothing more complex than directories in a computer file system. A single server can deliver dozens of them without any problems.
MySQL is definitely up to this kinds of security. Hosting providers run multi-tenant servers routinely.
I would consider MariaDB (a MySQL-compatible database written by MySQL's founder) over MySQL, as it supports roles.
Neither of them support Row Security like Oracle does, but you can mimic it by adding an "owner" column with the name of the role that can select/update the row.
Add a WITH CHECK OPTION view that checks that the current_user is in the role specified in that column.
Add a trigger to set owner value properly.
update: If you can't alter the table but can add new ones, add a new one w same key as original, and add owner column, and join the tables in your view.
See
http://www.sqlmaestro.com/resources/all/row_level_security_mysql/

MySQL: How to avoid a user from even seeing I have other DB's and grant select access to one view on one DB?

I have several DB's in my server, and I need to allow one user to select records from a view in one of the DB's. But I need for this user to not even see that there are other DB's nor see that there are other tables in the DB where the view belongs. Is this possible?
I had an account with a hosting company, a shared hosting account, and I could only see my DB when I accessed it through phpmyadmin. This is similar to what I need. Thank you for your help.
I've found the overview contained in this article even more helpful than the actual MySQL documentation for describing the big picture of how MySQL privileges are granted or denied.
The gist of the overview article is that privileges are controlled by a series of increasingly finer-grained permissions tables in the mysql database: mysql.user, mysql.db, mysql.host, mysql.tables_priv, mysql.columns_priv, mysql.procs_priv. The general rule is that a "Y" value for a privilege in a more fine-grained table overrules a "N" value in a more coarse-grained table. So the recommended strategy is to start by denying most privileges in the user table (which gives the coarsest control), and then make only the specific overrides that you want in the more fine-grained tables.
In particular, there is a privilege called SHOW_DATABASES which is determined by the Show_db_priv column in the mysql.user table; you'll want to set this to "N" for the user in question (and as described above, you may want to set most other permissions in the user table to "N" as well) and then grant only the privileges that the user actually needs in the mysql.db or mysql.tables_priv table or whatever would be appropriate for your particular case.
You have to add a user to a database using grant privileges.
Create new databases and simply don't add the user to it then the user won't be able to see it.
The only way the user will be able to find the database is if they try to access it and guess the database name. So basically a user/hacker would have to attempt to connect to a bunch of random database names in order to find one that says "access denied"

User with no permissions can still SELECT

I'm fairly new to MySQL and I've been creating test tables, etc.
Anyway, I created a new user, using
CREATE USER 'myUser'#'localhost' IDENTIFIED BY 'myPassword';
Now, when I log into this user, I can SELECT from a table I created with root earlier. Surely this should not be possible? The user has no SELECT permissions, or indeed any permissions. If (logged in as root) I do either:
SHOW GRANTS FOR 'myUser'#'localhost';
Or
SELECT * FROM information_schema.user_privileges WHERE grantee LIKE "'myUser'#%";
I can see they only have USAGE permissions. My understanding is this permission is set to indicate a user has no permissions.
So how is this user able to SELECT from my table?
If I do:
SELECT * FROM information_schema.table_privileges;
No results are returned.
What am I missing here? Are certain things like SELECT implicitly granted to new users? Do I have to explicitly revoke this?
If so, what other permissions are implicitly granted?
Ideally what I'm aiming for is a user that can do nothing except run one (or more) stored procedures that I specify with GRANT EXECUTE ON.
It never even occurred to me that you would be creating production tables in a test schema -- but it turns out this is documented in the MySQL refman (emphasis added):
In addition, the mysql.db table contains rows that permit all accounts
to access the test database and other databases with names that start
with test_. This is true even for accounts that otherwise have no
special privileges such as the default anonymous accounts. This is
convenient for testing but inadvisable on production servers.
Administrators who want database access restricted only to accounts
that have permissions granted explicitly for that purpose should
remove these mysql.db table rows.
So that explains your find that "Either way, even with deleting it and then recreating it, if it has the name 'test', it will always be accessible to anonymous users, etc."
During my testing, I created a schema called 'test'. Unknown to me, 'test', is actually some sort of reserved database schema name for MySQL. Anonymous users can use it, etc.
As a result, the stuff I was creating in there for testing purposes didn't have certain permission restrictions that other databases would have done.
I can't really find any information on this beyond this page:
http://www.greensql.com/content/mysql-security-best-practices-hardening-mysql-tips
That page says that it comes with it, but I'm pretty sure my installation didn't have it by default.
Either way, even with deleting it and then recreating it, if it has the name 'test', it will always be accessible to anonymous users, etc.
I hope this helps someone, I spent too long puzzling over this!

How can I make some tables read-only but allow users to create new ones?

I'm working on some data project with a few other collaborators. Most are fairly new to SQL so have inquired if I can make the 'raw' data tables read-only so they aren't accidentally altered, how would I go about doing that? Currently all users have GRANT SELECT ON mydb.* TO 'user'#'%' permissions, but I need to be a little more open.
There's a question about making a single table read-only, but it seems like it would deny users the ability to make other tables; or if they did, they couldn't do anything with them. There doesn't seem to be (or I can't find) a 'deny' setting like in NTFS that overrides allow/GRANT; from what I read REVOKE is only the opposite of a prior GRANT, you can't "nest" them.
I was considering making a separate 'raw' database that would be SELECT-only so users could copy it into the 'workspace' database, but that seems a bit hacky and will eat up some semi-significant amount of space on my budget cloud server. What's the proper solution?
GRANT SELECT ON example.* to 'someuser'#'somehost';
Give read only privilege.
GRANT CREATE ON example TO 'someuser'#'somehost';
Give create table privilege.
You can make a single MyISAM table read only by compressing the table. Use myisampack on the command line to pack the table.
More info can be found in the MySQL Manual: http://dev.mysql.com/doc/refman/5.0/en/myisampack.html

Prevent delete/update for tables by even superadmin/dba?

There are some mission critical tables which i need to ensure never get deleted or edited. only possible action is to read from it and the dba can add more rows. That's it.
Now for added security i want to prevent even the dba from being able to delete/alter the records, so basically no one can ever delete or alter a record, no super admin also. These tables are critical for activity tracking of certain type of users who's data i need to preserve indefinitely and some are critical lookup tables. So a mixture of system locked values and user tracked values.
Idea is if someone wants to destroy the data they need to kill that database. Is there a way to do this?
No, not possible, the superuser is always in control of the database. You could REVOKE update and delete permissions, but a superuser can always GRANT these permissions to himself again.
There is no way you can prevent a superuser to do something. The only thing you can do is prevent ANY user from ACCIDENTALLY deleting or updating the records. This can be achieved by creating rule on update and on delete.
CREATE [ OR REPLACE ] RULE name AS ON event
TO table [ WHERE condition ]
DO [ ALSO | INSTEAD ] { NOTHING | command | ( command ; command ... ) }
See this link for reference.
For MySQL, the following approach can be taken.
Once you have your application accounts in place, drop the superuser account (really, any account "WITH GRANT OPTION"). The system admin accounts should only have permission to stop and start the system, but not to read from your sensitive table.
Next, alter your table so that it uses the MEMORY engine. This means that the application administrator (not the DBA) will need to restore the contents whenever the database is restarted. It also means that the DBA cannot restart the database with the "skip-grants" option to gain access to the data - because the data will evaporate during the restart. (However, the system's root user can always dump the system memory and find your data in that.)
A better approach is to encrypt your data in the application with a key only known by the application administrator.