Remote access to MySQL - UNSAFE? - mysql

Is it unsafe to open the mysql server port to allow remote connections?
If it is unsafe, what is a better solution?
EDIT:
-I need read and write rights.
-Each user has a password to connect. That means that not any user can connect to the database.
What security problems does this enviroment have?
Is there a better solution?

In principle, MySQL has a rigorous permissions system which could be set up to allow remote users minimal levels of access to the tables they would need to do their job.
In practice, MySQL has had many exploits in the past, both in applying those permissions and in preventing access to the host server. It is reasonable to expect more in future; since very few admins allow untrusted access to a MySQL server, it is not strongly locked down against attacks (unlike, say, a web server like Apache).
MySQL's authentication model is also weak: passwords are stored in a table as unsalted hashes and there is no protection against brute-force password attacks. For communication between a trusted server app and the DB, you can get away with that; for authentication of not-wholly-trusted third parties it's not good enough.
If your “users” are database administrators, it's plausible to give them remote access, with access locked down by IP address/firewall or SSH tunnel. If the “users” are not-fully-trusted third parties you expect to be using the database as part of a client application, I wouldn't. And definitely don't open access to the whole public internet.
In any case, if we are talking about application users, your business rules are going to need more granularity in access rights than you can manage with table- or column-level controls. For example rules like “reviewer-class users may set article.state to 3 but only if article.state was previously 1 or 2”, or “setting article.state to 4 always causes the associated articlecontent to be deleted” cannot be reproduced in table permissions.
For that, you almost always need some component between the raw table storage and the remote client/application to manage the requests. That layer is traditionally a separate server application which is the only thing talking to the database. You could in theory write that component in database stored procedures, and give users access only to the procs not the tables. But doing anything complicated in stored procs is a super pain to write and maintain compared to a general-purpose programming language.

Related

Who is the user in MySQL?

I'm starting to learn the basics of developing database applications (I want to learn MySQL specifically), but I'm unable to determine how the structure of the application should be. Say my system serves the students of a school (records grades, etc.), where the client side is a GUI application written in C++/Qt talking to my server computer over the internet.
My question is What is the natural/correct way to implement this?
Do I encapsulate the SQL queries directly in the GUI program, and
thus making every student a user of the MySQL database, and thus
assigning a database user for each student?
Or should the encapsulation occur in a server side application that I
write that represents the link between the GUI application and the database
server? (I.e. the server side application is the client side of the
MySQL system.)
In other words, who is the user of MySQL? My server side application or the users of my client side application?
In both cases (wide client -- client-DB or thin client -- client-server) it is enough to have only 1 MySQL user.
You will store it's user and password in application settings (usually hidden from regular student/customer).
And you will grant those rights to application username, not to the student.
It is the role of application to control the user rights.
Safety:
For the thin client, it is usually safe, but it will introduce the need to use API-key that has its danger.
For wide client architecture it is dangerous enough, so:
usually, such applications work in-house
MySQL user has those rights that protect the data from full destroying (at least forbid tables dropping).
grant privileges to the user on SPECIFIC HOSTs
make backup copies on the hourly or daily basis depends on the
size
it is good to store the password, not in open form but
encrypted

is a password necessary if mysql only allows connections from localhost

On a lot of public webpages, hosted by people at their own homes, they use their own desktops as webserver. Within this kind of setting usually I use a form of server sided language (like php) that connects to an MySQL server on the same machine. When installing this I always give an password to the “root” user and create a new user and password for the application (the php) script to use. Because both script and database are on the same “localhost” I always set the allowed connection to only allow connections from the local host and not from anywhere else. So both “root” and other “users” can only connect from when accessed from within the machine.
(the separate “root” and “user” accounts are made to give them separate privileges and an user can not drop scheme’s for example)
Today it struck me, why am I setting passwords in MySQL? Because if you want to connect to this database you already have to been logged in in the local machine. So, is setting passwords really necessary or just a redundant precaution?
And if it’s NOT an redundant precaution, why is it unsafe to not set a password.
(not that it is a big burden, but I have to remember all these passwords somehow, using encrypted systems this is not a real big problem, but if it could be avoided than……)
The comments on your post have mostly summed this up, but as far as I am aware, this is known as "Defense in depth" (See 1 and 2). Defense in depth is basically about avoiding having a single point of failure in your project - If your webserver is compromised, having a weak password means that you're just giving away your database for free. This would be equivalent to somebody breaking into your house to find you've placed your safe on the kitchen table and unlocked it.
If you're hosting an externally facing website that you hope to get a decent amount of traffic, making it as secure as possible is a good idea, unless you particularly like the idea of malicious users having direct access to your home network. That said, if you are expecting a decent amount of traffic I highly recommend hosting your website elsewhere - You may find that your home internet speeds suffer greatly as a result.

Storing MySQL credentials in a MySQL database

This is a similar question to "Storing MS SQL Server credentials in a MySQL Database"
So, in theory, imagine I have 1 MySQL server. I have a "master" database, and then X number of other generic databases. What im looking for, is a way of using an app (for arguments sake, lets say a web app, running on php) to first access the master database. This database then needs to tell the app which database to connect to - in the process, giving it all the credentials and username etc.
How is the best way around this?
The three ideas I have so far
Store the credentials in the master database for all the other databases. These credentials would of course be encrypted in some way, AES probably. The app would get the encrypted credentials, decrypt, connect.
Store the credentials elsewhere - maybe a completely separate server. When the master database is accessed, it returns some sort of token, which can be used to access the credential storage. Again, encrypted via AES.
Using some sort of system that I am not aware of to do exactly this.
Not doing this at all, and come up with a completely different approach.
To give a little example. "master" would contain a list of clients. Each client would contain it's own separate database, with it's own permissions etc.
I've had no reason to do this kind of thing myself but your first two ideas sound good to me and (as long as you include server address) not even necessarily separate ideas (could have some clients on the server with master, and some elsewhere) the client logic won't need to care. The only issue I can see is keeping the data in the "master" schema synced with the server's security data. Also, I wouldn't bother keeping database permissions in the master schema as I would think all clients have the same permissions, just specific to their schema. If you have "permissions" (settings) that limit what specific clients can do (perhaps limited by contract/features paid for), I would think it would be much easier to keep those in that clients' schema but where their db user cannot change data.
Edit: It is a decent idea to have separate database users in this kind of situation; it will let you worry less about queries from one user's client inadvertently (or perhaps maliciously) modifying another's (client account should only have permissions to access their own schema.) It would probably be a good idea to keep the code for the "master" coordination (and connection) somewhat segregated from the client code base to prevent accidental leaking of access to that database into the client code; even if encrypted you probably don't want them to even have any more access than necessary to your client connection info.
I did something like this not long ago. It sounds like you're trying to build some kind of one-database-per-tenant multi-tenant system.
Storing encrypted credentials in a directory database is fine, since there's really no fundamentally different way to do it. At some point, you need to worry about storing some secret (your encryption key) no matter what you do.
In my use case, I was able to get away with a setup where the directory just mapped tenants to db-hosts. The database name and credentials for each tenant were derived from the tenant's identifier (a string). So something like, given a TenantID T:
host = whatever the directory says.
dbname = "db_" + T
dbuser = T
dbpass = sha1("some secret string" + T)
From a security standpoint, this is no better (actually a bit worse) than storing AES encrypted credentials in the directory database, since if someone owns your app server, they can learn everything either way. But it's pretty good, and easy to implement.
This is also nice because you can think about extending the idea a bit and get rid of the directory server entirely and write some function that maps your tenant-id to one of N database hosts. That works great until you add or remove db servers, and then you need to handle shuffling things around. See how memcache works, for example.
You can use Vault to do this in much systematic way. In fact this is a strong use-case for this.
Percona has already written a great blog on it,

Additional prevention of Database tampering

Is it possible to prevent someone other than those allowed from tampering with the database. I guess I am asking if there is an method other than the database login to hamper people from tampering with the database? I am aware of privileges and how only access to certain parts of the database for certain users. I am looking for something more in case someone manages to ascertain the correct username/password combination.
I am using this database in conjunction with a web server. The database server and web server are on different machines and behind a hardware firewall. The web server is only accessible through the firewall, and the database server accessible only through the web server.
I guess what I am asking is would it be feasible to create some sort of user control that creates a session id or something similar so that only if that id matches that stored when the user signed on will the query be run.
Yes you have some control on setting which user has what privilege. Of course if they get a hold of the root user password, then I think you may be out of luck.
Check out this link for some information regarding Granting/Revoking privileges.
http://beginner-sql-tutorial.com/sql-grant-revoke-privileges-roles.htm
Granting Syntax (from link)
GRANT privilege_name
ON object_name
TO {user_name |PUBLIC |role_name}
[WITH GRANT OPTION];
Revoke Syntax (from link)
REVOKE privilege_name
ON object_name
FROM {user_name |PUBLIC |role_name}
More: Brian added as a comment that Symantec has a nice guide to securing MySQL. I just wanted to add that it contains a lot of very useful information as well, http://www.symantec.com/connect/articles/securing-mysql-step-step
The best way to prevent people from tampering with it is to put it on a server that can only be accessed from the other machines that need to talk to the database (such as a web server)
If possible, the web-servers shouldn't have any administrative access except through a local network or a VPN.
If cost is an issue (you only have one server perhaps or a shared host) If you can run MySQL over an SSL connection, at least then the passwords aren't sent in the clear.
Update your OS for any security fixes that could lead to privilege escalation or remote code execution and use a firewall to block every ports beside the one you need. You could use SSH tunnels if your database needs remote access. Filesystem access or shell access may be a way to tamper with the database.
Use multiple credentials with according privileges. Use read-only access to logins that doesn't need write access.
Please explain a bit your environment and your situation and typical usage, that would help up to pinpoint potential flaws.
Read up on SQL Injection attacks and make sure your code will not allow them.
If you do not use dynamic SQl and use stored procs instead, you can put permissions at the proc level and users can only do things through the stored proc as you can prevent direct insert, update and delete to the tables. This helps prevent fraud because the users can't do anything except what the developers have written. So no one can delete a whole table, etc. Do not give developers production rights other than select rights. Encrypt your backups. Remember employees are as big or bigger threat to your data as outside attacks.
In some databases a password for the sys admin is not required. Always use one. Do not give it out to anyone more than you must.

Keep database information secure

there's this interesting problem i can not solve myself. I will be very glad, if you help me.
Here's it:
there are many client applications that send data records to one MySQL server.
Few data records are not very important, but the whole database is. (You can imagine it is facebook DB :) )
Is there any way to ensure that
data from DB won't be used by anyone but true owner
DB will preserve essential features such as sorting etc.
assuming that attacker can mysteriously gain full access to server?
You can't simply encrypt data client-side and store it encrypted, since client application is wide-spread and attacker can get key from it.
Maybe adding some layers between application and DB, or combining encryption methods client- and server-side (using mysql built-in methods) will help?
As long as the database needs to start up and run unattended you can't hide the keys from a compromised root account (= 'mysterious full access'). Anywhere the database could possibly store the master key(s), the root will also have access. No amount of business layers or combination of client-server encryption will ever circumvent this simple fact. You can obfuscate it till the day after but if the prize is worth then root can get it.
One alternative is to require a manually assisted start up process, ie. a human enters the master key password during the server boot (or hardware module PIN), but this is extremely hard to maintain in real world, it requires a highly trusted employee to be on pager call to log in and start the database whenever there is downtime.
Solutions like TPM offer protection against physical loss of the server, but not against a compromised root.
Your root is as important as the database master key(s), so you must protect your root with the same care as the keys. This means setting up operating procedures, screening who has access to root, rotating the root password and so on and so forth. The moment someone gains 'mysteriously full access' the game is pretty much lost.
I pretty much agree with Remus Rusanu's answer.
Maintaining good security is hard, but you can always pay attention to what you do. When ever you access sensitive information carefully verify your query and make sure it cannot be spoofed or exploited to gain access to information which shouldn't be accessible by given client.
If you can roll out physical access to the box by the attacker then there are several things you can do to harden your security. First of all I'd configure ssh access only to only allow connections from specific IP or IP range (and of course no root access). You can also do that that on your firewall. This would mean that the weakest link is your server (the application which receives data/requests from clients, could be web-server and whatever scripts you use). Now you "just" have to make sure that no one can exploit your server. There are a lot more things you could do to harden your system, but it think it would be more appropriate to ask on ServerFault.
If you're worried about physical access to the PC, there isn't really much you can do and most stuff has already been mentioned in Remus answer.
There's also another option. This is by far the most ineffective method from speed and ease to develop viewpoint, but it would partly protect you from any kind of an attack on your server (including physical). It's actually quite simple, but a bit hard to implement - only store the encrypted data in the database and handle all encryption/decryption client-side using javascript or flash. Only the client will have the key and data will always be transfered over the wire and stored in encrypted format. The biggest drawback is that once client forgets the key there's no way back, the data is inaccessible.
Of course it's all matter of time, money and effort - with enough of these anything can be broken.
I've no idea if such a thing exists in MySql, but row-level-versioning in Oracle enables you to define access rights on row-level IN the database: so that means, regardless of what tool is being used to access the data, the user only ever sees the same selection as determined by his/her credentials.
So if my username/role is only allowed to see data limited by some WHERE clause, that can appended to each and every SELECT that appears in the database, regardless of whether it comes from a web app, a SQL querying tool, or whatever.
I will use a 2nd layer and a firwall between them.
so you have firewall ---- web server --- firewall -- 2nd layer server --- firewll --- db
it will be wise to use different platfroms between layers, it all depends how important is the data.
anyway - the web server should have no access to DB.
about preserving sort - if you use a file encrypotion mechisim - it will only protect you from Hard drive theaft.
if you encrypt the data it self, and if you do it smartly (storing the keys in a separate place) you will not loose sorting as you will look for the encryoted entry and not the real one- but now you have another thing to protect....