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.
Related
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.
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.
Obviously, we don't want to hardcode the plaintext password in each script. This would make cycling the password difficult since a ton of scripts would need to be changed in addition to the password being in plaintext in the first place.
If the scripts takes the password as a parameter, then we need to worry about modifying the 'ps' output to not show the password argument's value. We would also have to worry about the command being recorded in shell history. This can be potentially handled via HISTIGNORE/HISTCONTROL on bash, but there are other shells in use with differing and less flexible history control (e.g.: zsh).
We could also use a commandline-specific environment variable (FOO=bar ./script), and while the 'FOO=bar' won't show up in 'ps', it's still, by default, recorded to the shell history. Besides, some systems expose other user's process environments (via 'ps') anyway.
A password (configuration) file could be used that simply stores the plaintext password. This file could be owned/permissioned such to tighten up its access. But, at the end of the day, you still have a password in plaintext.
Prompting is also an option, but this tends to be less convienient (still possible via expect, for example, though) and complicates non-interactivity if the script requires such.
Encryption of some flavor could be used but then we still have a similar issue to deal with with the decryption key.
Should I just go with one of the above anyway? Are the other options that might be superior? How do people handle this situation is a secure manner?
The general goal here is that an attacker should not be able to comprise the database server if the attacker somehow gets onto a system that makes use of the database server. For example, an attack shouldn't be able to just find the password lying around somewhere, shouldn't be able to observe the system ('ps') to discover it, and shouldn't be able to "look back in time" (shell history) to find it.
I'm perfecting aware that there are a millions of scenarios (kmem, swapped pages, etc.. etc..) and that most bets are off if the attacker gets root or physical access and that nothing is going to be 100% secure. I'm just really looking for the best approach within reason. :-)
You can put a .my.cnf file in the home dir(s) of users that can access the script, with their info and mysql can read it from there instead of the command line. You'll also have to set an environment variable to point at ~/.my.cnf, but... I'm not sure if it's MYSQL_HOME or SYSCONFDIR or something else*. It'd still be a plain text file, but if you restrict that file to owner-only, it should be fine? It'll at least keep passwords out of ps.
MySQL: Option Files and MySQL: Password Security doc pages both hint at this a little.
(*disclaimer: I'm no admin by any definition, just enough to get in trouble)
If the scripts don't use prompting, and somehow know the db password then the attacker can execute any of your scripts and do those same things.
If you ask for a password, you will have to give it to some people, who will put it in their scripts, or make a password for each user, which provides multiple passwords to guess (and they'll still put it in their scripts).
Perhaps one thing to consider is to have a no password user that can do only SELECT on appropriate tables and can only login from particular hosts, and to require passwords and other users for more sensitive functions?
If you want to hide the password, you could always have a 2 part system. Although you can do very complicated things, XOR (bitwise exclusive or, which is in perl and most other languages) can also be your friend. It is simple for the admin and for the attacker no one piece is useful. An automated attacker might move on to more fertile ground. You can even keep one of the parts on another host and fetch it with wget or nfs or whatever. That way it could be shut off as part of a tripwire system.
Meanwhile, maybe you need some tripwires or honeypots of sorts, so that if the bad guys come calling you can give them disinformation or even shut things off quicker. I like fail2ban for active firewalling. It can scan log files and block ip addresses that are sending you crud you dont want based on anything that is showing up in your logs. It uses regexp's and any log file to define an incident and has some flexibility in the rules engine.
I am not a unix admin, but... How about having the scripts run under a no-login account, and set the permissions on the script (and password file) to be 500. That would limit access to root and the script user.
Depending on how critical the data is, you could implement various measures.
Store the password in a file readable only by root. The script reading the keys should start as root, read the password, establish the database connection using database account with minimum privilege required, wipe password from memory, and then drop down (How can I drop privileges in Perl? may help) to a non-privileged system account.
Have simple scripts/trigger to monitor database sessions (session start and end time, user, ip address, commands executed) on the database server, monitor use of sudo on the system, etc.
You might like to explore TPM (http://en.wikipedia.org/wiki/Trusted_Platform_Module)
Many security products use TPM for storing critical security related keys. Other idea could be encrypt the password using certificate stored in a smart card.
Cheers,
GK
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.
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.