I have a form that users can fill out, and the data will be stored into a MySQL database using PHP. The connection to the Apache server is encrypted through HTTPS, and I would like to encrypt the connection to the MySQL database. Both Apache and MySQL are on the same server machine.
I digged around the Interweb and Stunnel seems to be what I need. OpenSSL and SSL are supported and activated on the server, since the we are given the option of using the standard port and a stunnel port to connect to the MySQL server. However, all the articles I found online deal with using Stunnel to connect a MySQL client to an external MySQL Server, but not how to use PHP to connect to a local MySQL server. Am I right to assume that just because the form is transmitted through https, it doesn't mean that the connection to the database is also encrypted?
The PHP code I use to connect to MySQL is like this:
$mysqli = new mysqli("ip","user", "password", "database", "standardport");
This works fine using the standardport. However, if I change it to a Stunnel Port, I get a connection time-out error. Clearly I'm missing something; any help and advice is appreciated! Thanks!
You've already stated that you use an HTTPS connection to encrypt traffic between the clients browser and your webserver, and that the webserver and MySQL instance are on the same machine.
Assmuning the HTTPS connection is secure, this should be all you need to protect your data over public networks, and using a secure tunnel for a connection that is only present on the local machine simply adds an unnecessary layer of complexity.
Consider the following examples.
The first is how the connection looks without a secure tunnel.
browser <--HTTPS--> [ webserver <--> mysql ]
So in this scenario, the the connection between the webserver and mysql is unencrypted. Someone who has access to the machine (depending on permissions) will be able to observe all traffic between the webserver and/or read the physical databases from disk themselves.
Now, with a secure tunnel
[ webserver <--> stunnel <--ENCRYPTED--> stunnel <--> mysql ]
I hope you can see that the connections between the webserver and one secure tunnel endpoint, and the connection between mysql and the other endpoint are both unencrypted. In this scenario, exactly the same as before, someone with access to the machine could potentially see all traffic and read the databases from disk.
No additional security has been achieved.
Lastly
[ webserver <--> stunnel ] <--ENCRYPTED--> [ stunnel <--> mysql ]
When you are using two separate servers, then the local traffic is still unencrypted, however stunnel secures the stream between the two machines. Someone with local access to the machines may still be able to observe traffic and read data, however someone observing network traffic between servers will not.
A solution?
All that said, if you really want to encrypt the traffic between PHP and MySQL, even on the same machine, a slightly better solution exists than using stunnel.
MySQL supports SSL natively, as does PHP when both are compiled with SSL support. (Your installations may already be configured this way, it's up to you to check them)
The MySQL manual details how to configure your MySQL server with SSL support and PHP provides the function mysqli_ssl_set
Using this combination, you can natively encrypt the connection between PHP and the mysql server.
[ webserver <--ENCRYPTYED --> mysql ]
However someone with access to the machine may still be able to read the unencrypted database from disk, and may be able to observe the memory of running processes.
You are quite right, the internet is a dangerous place, and proper security is essential. If your server itself and the data it contains are not secure, all is lost, no matter what precautions you take securing how the data enters and leaves it.
Related
I've spent quite some time now trying to figure out how to pass a few rows from a server inside a SonicWall VPN to a remote VPS cloud server. The server inside the VPN is Microsoft 2003 running SQL Server 2005, the destination server is a CentOS 6 with MySQL. I've been unable to find a way for the CentOS to easily and securely access the MSSql server from outside the VPN. I have extremely limited knowledge of SonicWall or other firewalls in general and I really don't want to open the door to security risks. So in light of this I've come up with the following solution:
1) A scheduled PHP script extracts the rows and encrypts them in AES-256 inside a password protected excel file
2) The script then uploads the excel file to my remote server using FTP
3) The remote server, having the same encryption keys, decrypts the file and uploads the rows to the MySQL database.
Two questions:
1) Is this a safe method of moving sensitive data from one server to another?
2) Is there an easier way to access the data that I have not thought of?
You're involving FTP and files for what is essentially a system-to-system transfer which can result in trouble due to file locks and just looks ugly.
A better approach would be to have the remote CentOS box expose a port / web service that is exposed by HTTPS which requires client side authentication :
Your script retrieves the rows from some source
The script converts the rows to a form the server can read
The script calls the port exposed by the client, this is an outgoing connection so should be easier to get outside the VPN (based on the fact that getting an FTP connection outside the VPN is possible)
The script verifies the server side certificate and provides it's own client side certificate and transmits the rows over SSL
The CentOS host receives the rows and processes them as required.
With your current approach you will need to secure the FTP connection somehow, to do so securely will require both the service and client to authenticate themselves to one another and SSL does most of the heavy lifting in that regard in terms of connection negotiation and protocol flow.
I'm using the following to connect to a mysql database from the localhost
<?php
function testdb_connect ()
{
$dbh = new PDO("mysql:host=localhost;dbname=test", "testuser", "testpass");
return ($dbh);
}
?>
However when I tried to connect to this database (database is running on ec2-12-34-56-78.compute-1.amazonaws.com) from a different server, using the following code
$dbh = new PDO("mysql:host=ec2-12-34-56-78.compute-1.amazonaws.com;dbname=test", "testuser", "testpass");
I'm unable to connect.
Is it possible to connect to a remote database on an ec2 instance with php pdo?
How would I pass an authentication parameter (ex. private key)
You should probably consider using RDS for your database rather than implementing on EC2 unless you have a very unique database that requires a high degree of customization (i.e. clustered configurations, etc.). Running on EBS-backed volume (which you would need to do to be able to persist the physical data files), will subject you to slow disk I/O. If you are not running on EBS-backed EC2, then your data is transient and can not be considered as being on reliable physical storage. If this is OK for your design (you just need transient info in your database), then you would probably be even better served but just putting your information into Elasticache or some form of in-memory cache.
RDS uses MySQL (well, you can also opt to use Oracle). You would access it EXACTLY like you would access your own MySQL server (same PHP abstraction, same SQL, same almost everything (you don't get root access, but rather a form of super-user access). RDS also provide you easy to implement (i.e. push button) configuration for multi-az (high-availability, synchronously-updated standby), replication slaves, DB instance re-sizing, and data snapshots.
In either case (for RDS or EC2), you would need to make sure that your EC2 or RDS security groups allows access from the EC2 instances (or other servers) that host your application. In case of EC2 only you could either place the servers in the same security group, and provide port 3306 access on that group, or better would be to create two security groups (one for app and one for db). In the db security group provide port 3306 (or whatever port you are using) to the security group(s) to which the app server(s) belong.
For an RDS, you would need EC2 security group for app server(s) and a DB security group for the RDS instance). You would need to provide access to the app server security group in the RDS security config.
I don't know the specifics of how this might work with AWS but the first thing I would do is get an SSH tunnel running between the machines.
Then PHP/PDO would basically just think that you're connecting to a local database. In my experience it also makes the connection faster to establish as it doesn't have to do a DNS lookup to find the remote server... quite a big deal when you think that every PHP page load might have to connect to the remote DB.
I use this on intranets when an application needs to manage data stored on a remote database and it works like a champ.
I find SSH tunnels perfectly stable but I use a program called autossh to attempt to reconnect SSH tunnels when they go down.
For completeness here's the command I use to start autossh so it establishes and maintains a particular SSH tunnel. Added here because I found the autossh docs pretty confusing to work out what options I wanted.
autossh -M 0 -f -L3307:127.0.0.1:3306 -p 22 -N -f username#xxx.xxx.xxx.xxx
This forwards port 3307 on your web server to 3306 on the remote DB server. So in PHP you would connect to 3307. You could choose 3306 if you wanted, I chose local port 3307 just in case you had a local MySQL as well as a remote. The -p switch is the port that SSH is running on on the remote machine.
You can add this command to /etc/rc.local (on CentOS at least) to establish the SSH tunnel on server start.
Hope this helps!
I need to connect to a webservice which is behind of a VPN via PHP. My server is Debian Linux (Squeeze).
Is it possible to accomplish this via PHP on Linux?
Is it risky to do this if it is possible? (When VPN connection hangs etc., does the operating system or any other what-so-over handles the situation)
I have only one network card, therefore I really wonder whether it is possible to keep server online for normal users while "posting data over an accomplished VPN connection in the background".
Although my question seems to a conceptual question, any specific help is also welcome.
Server OS : Debian Linux Squeeze (x64)
Web Server : Apache HTTP
PHP Version: 5.3
Framework: Symfony 1.4
VPNs are at a network layer below PHP, PHP won't know or care that the connection is over a VPN or a normal connection. It's handled by the network stack.
If you use a permanent one (e.g. IPSEC) then PHP doesn't need to create the connection, it's just there to use when PHP connects to an IP address that is in the VPN. It is selected to use by the network layer when it does the routing, not by PHP. This is true even if you create the VPN on demand, as jderda suggested using exec() or similar. But a permanent connection is better (IPSEC).
So to answer your questions:
The question doesn't make sense, the only way PHP could do this is using PPTP or similar and exec() to bring the connection up, but better to use IPSEC
If the VPN connection hangs/dies PHP won't get a connection to the remote end and will timeout the connection.
Yes it is.
From PHP point of view, the VPN is just a plain network connection. It does not require additional handling.
If you want to dynamicaly estabilish a VPN connection, you'll probably need to use exec() and some commandline tool for estabilishing a connection. But as such connection doesn't interfere with normal network communication (as long as it's properly configured, with other subnet ip range), you should estabilish it once and keep it active for PHP and other apps to use.
I'm in the unfortunate position of having to sync a local microsoft access database with a remote mysql database.
I have written a php script which will sync the databases every 10 minutes. However I'm definitely concerned about security.
So far I have set up remote mysql with cpanel, this allows only my I.P address to make connections. I've also made sure the user I'm connecting with has limited permissions.
However, I'm aware that the data I'll be sending back and forth will be unencrypted. Is there anything I can do to make sure my data is encrypted? I'd also like to know whether my mysql username/password is currently encrypted the way I have it set up?
Lucas
You can use secure connection to MySQL:
MySQL side: http://dev.mysql.com/doc/refman/5.5/en/secure-connections.html
PHP side: http://php.net/manual/en/mysqli.real-connect.php (MYSQLI_CLIENT_SSL flag)
I have not worked with SSL connections to MySQL with PHP, but, I think it is not hard to find needed information on http://php.net, http://dev.mysql.com and http://google.com
Update
This may help: http://www.madirish.net/node/244, PHP to MySQL SSL Connections, http://www.php.net/manual/en/mysqli.ssl-set.php
You could use the PHP mcrypt functions to encrypt and decrypt the data.
A good example of this can be found right on SOF: Best way to use PHP to encrypt and decrypt?
I need to be able to encrypt the MySQL traffic from a web server to a database server. I know how to set MySQL to use SSL based on the server and client settings in my.cnf however, this needs to be done using mysql_connect() in PHP. This may be a 2 part question.
1) Does mysql_connect() use the MySQL client settings that are set in my.cnf?
If not...
I have read that you can use MYSQL_CLIENT_SSL however, where is the SSL data obtained from? Does using MYSQL_CLIENT_SSL in the mysql_connect function automagically encrypt the traffic?
Simply put, what is the best way to do this?
Thanks!
If you connect to MySQL using SSL, all your traffic between your SSL client and server will be encrypted.
MYSQL_CLIENT_SSL is obsolete. Using mysqli if you need to use SSL,
$db = mysqli_init();
$db->ssl_set(null, null,'cacert.pem',NULL,NULL);
$db->real_connect('host','user','pass','db');
As an alternate solution, you can also use SSH tunnels to accomplish compression and encryption.
MYSQL_CLIENT_SSL was removed from PHP and should not work.
You have a few options: the first is that if your web server is also your database server, you don't need encryption because the connection never leaves your box: it just uses localhost.
The second option is to use what Pablo suggested above and take advantage of SSH tunnels. An SSH tunnel essentially does the same thing as an SSL connection, except it takes one "extra step" to get it going.
This seems like a pretty decent tutorial to help get you started:
http://www.revsys.com/writings/quicktips/ssh-tunnel.html
Hope this helps!
According to http://www.php.net/manual/en/mysql.constants.php#mysql.client-flags MYSQL_CLIENT_SSL is still part of PHP 4 and 5. You need to set up the SSL connection beforehand though. You'll have to generate certificates and a bunch of other hassle (http://www.madirish.net/?article=244) but it will encrypt the traffic between your web server and your database host.
As mentioned above, if your web server is on the same host as the database server this encryption is unnecessary as the data travels over a local socket and isn't exposed to the network. The SSL encryption only encrypts traffic over the network.
I would warn against using an SSH tunnel because they have a tendency to die and you'll have to worry about maintaining the connection.