FIGURE 15.4 SSL breaks up, compresses, hashes, and encrypts data before sending it. One thing you might notice from the diagram is that the TCP header is added after the data is encrypted. This means that routing information could still potentially be tampered with, and although snoopers cannot tell what information we are exchanging, they can see who is exchanging it. The reason that SSL includes compression before encryption is that although most network traffic can be (and often is) compressed before being transmitted across a network, encrypted data does not compress well. Compression schemes rely on identifying repetition or patterns within data. Trying to apply a compression algorithm after data has been turned into an effectively random arrangement of bits via encryption is usually pointless. It would be unfortunate if SSL, which was designed to increase network security, had the side effect of dramatically increasing network traffic. Although SSL is relatively complex, users and developers are shielded from most of what occurs, as its external interfaces mimic existing protocols. In the relatively near future, SSL 3.0 is likely to be replaced by TLS 1.0 (Transport Layer Security), but at the time of writing, TLS is a draft standard and not supported by any servers or browsers. TLS is intended to be a truly open standard, rather than a standard defined by one organization but made available for others. It is based directly on SSL 3.0, but contains improvements intended to overcome weaknesses of SSL. Implementing Secure Transactions with PHP and MySQL C HAPTER 15 15 I MPLEMENTING S ECURE TRANSACTIONS 335 Compress Calculate MAC Encrypt Packetize <html><head><title><My Page</title>…Our data d><title> M<html><hea y Page</tiData Packets Compressed data Message Authentication Code Encrypted Packets TCP Packets TCP header 19 7842 CH15 3/6/01 3:40 PM Page 335 Screening User Input One of the principles of building a safe Web application is that you should never trust user input. Always screen user data before putting it in a file or database or passing it through a sys- tem execution command. We’ve talked in several places throughout this book of techniques you can use to screen user input. We’ll list these briefly here as a reference. • The addslashes() function should be used to filter user data before it is passed to a database. This function will escape out characters which might be troublesome to a data- base. You can use the stripslashes() function to return the data to its original form. • Magic quotes. You can switch on the magic_quotes_gpc and magic_quotes_runtime directives in your php.ini file. These directives will automatically add and strip slashes for you. The magic_quotes_gpc will apply this formatting to incoming GET, POST, and cookie variables, and the magic_quote_runtime will apply it to data going to and from databases. • The escapeshellcmd() function should be used when you are passing user data to a system() or exec() call or to backticks. This will escape out any metacharacters that can be used to force your system to run arbitrary commands entered by a malicious user. • You can use the strip_tags() function to strip out HTML and PHP tags from a string. This will avoid users planting malicious scripts in user data that you might echo back to the browser. • You can use the htmlspecialchars() function, which will convert characters to their HTML entity equivalents. For example, < will be converted to <. This will convert any script tags to harmless characters. Providing Secure Storage The three different types of stored data (HTML or PHP files, script related data, and MySQL data) will often be stored in different areas of the same disk, but are shown separately in Figure 15.1. Each type of storage requires different precautions and will be examined separately. The most dangerous type of data we store is executable content. On a Web site, this usually means scripts. You need to be very careful that your file permissions are set correctly within your Web hierarchy. By this we mean the directory tree starting from htdocs on an Apache server or inetpub on an IIS server. Others need to have permission to read your scripts in order to see their output, but they should not be able to write over or edit them. The same proviso applies to directories within the Web hierarchy. Only we should be able to write to these directories. Other users, including the user who the Web server runs as, should E-commerce and Security P ART III 336 19 7842 CH15 3/6/01 3:40 PM Page 336 not have permission to write or create new files in directories that can be loaded from the Web server. If you allow others to write files here, they could write a malicious script and execute it by loading it through the Web server. If your scripts need permission to write to files, make a directory outside the Web tree for this purpose. This is particularly true for file upload scripts. Scripts and the data that they write should not mix. When writing sensitive data, you might be tempted to encrypt it first. There is usually little value in this approach though. We’ll put it this way: If you have a file called creditcardnumbers.txt on your Web server and a cracker obtains access to your server and can read it, what else can he read? In order to encrypt and decrypt data, you will need a program to encrypt data, a program to decrypt data, and one or more key files. If the cracker can read your data, probably nothing is stopping him from reading your key and other files. Encrypting data could be valuable on a Web server, but only if the software and key to decrypt the data was not stored on the Web server, but only existed on another machine. One way of securely dealing with sensitive data would be to encrypt it on the server, and then transmit it to another machine, perhaps via email. Database data is similar to data files. If you set up MySQL correctly, only MySQL can write to its data files. This means that we need only worry about accesses from users within MySQL. We have already discussed MySQL’s own permission system, which assigns particular rights to particular usernames at particular hosts. One thing that needs special mention is that you will often need to write a MySQL password in a PHP script. Your PHP scripts are generally publicly loadable. This is not as much of a dis- aster as it might seem at first. Unless your Web server configuration is broken, your PHP source will not be visible from outside. If your Web server is configured to parse files with the extension .php using the PHP inter- preter, outsiders will not be able to view the uninterpreted source. However, you should be careful when using other extensions. If you place .inc files in your Web directories, anybody requesting them will receive the unparsed source. You need to either place include files outside the Web tree, configure your server not to deliver files with this extension, or use .php as the extension on these as well. If you are sharing a Web server with others, your MySQL password might be visible to other users on the same machine who can also run scripts via the same Web server. Depending on how your system is set up, this might be unavoidable. This can be avoided by having a Web server set up to run scripts as individual users, or by having each user run her own instance of Implementing Secure Transactions with PHP and MySQL C HAPTER 15 15 I MPLEMENTING S ECURE TRANSACTIONS 337 19 7842 CH15 3/6/01 3:40 PM Page 337 the Web server. If you are not the administrator for your Web server (as is likely the case if you are sharing a server), it might be worth discussing this with your administrator and exploring security options. Why Are You Storing Credit Card Numbers? Having discussed secure storage for sensitive data, one type of sensitive data deserves special mention. Internet users are paranoid about their credit card numbers. If you are going to store them, you need to be very careful. You also need to ask yourself why you are doing it, and if it is really necessary. What are you going to do with a card number? If you have a one-off transaction to process and real-time card processing, you will be better off accepting the card number from your customer and sending it straight to your transaction processing gateway without storing it at all. If you have periodic charges to make, such as the authority to charge a monthly fee to the same card for an ongoing subscription, this might not be an option. In this case, you should think about storing the numbers somewhere other than the Web server. If you are going to store large numbers of your customers’ card details, make sure that you have a skilled and somewhat paranoid system administrator who has enough time to check up- to-date sources of security information for the operating system and other products you use. Using Encryption in PHP A simple, but useful, task we can use to demonstrate encryption is sending encrypted email. The de facto standard for encrypted email has for many years been PGP, which stands for Pretty Good Privacy. Philip R. Zimmermann wrote PGP specifically to add privacy to email. Freeware versions of PGP are available, but you should note that this is not Free Software. The freeware version can only legally be used for non-commercial use. If you are a U.S. citizen in the United States, or a Canadian citizen in Canada, you can obtain the freeware version from http://web.mit.edu/network/pgp.html If you want to use PGP for commercial use and are in the United States or Canada, you can get a commercial license from Network Associates. See http://www.pgp.com for details. E-commerce and Security P ART III 338 19 7842 CH15 3/6/01 3:40 PM Page 338 To obtain PGP for use outside the USA and Canada, see the list of international download sites at the international PGP page: http://www.pgpi.org An Open Source alternative to PGP has recently become available. GPG—Gnu Privacy Guard—is a free (as in beer) and Free (as in speech) replacement for PGP. It contains no patented algorithms, and can be used commercially without restriction. The two products perform the same task in fairly similar ways. If you intend to use the com- mand line tools it might not matter, but PGP has other useful interfaces such as plug-ins for popular email programs that will automatically decrypt email when it is received. GPG is available from http://www.gnupg.org You can use the two products together, creating an encrypted message using GPG for some- body using PGP (as long as it is a recent version) to decrypt. As it is the creation of messages at the Web server we are interested in, we will provide an example here using GPG. Using PGP instead will not require many changes. As well as the usual requirements for examples in this book, you will need to have GPG avail- able for this code to work. GPG might already be installed on your system. If it is not, do not be concerned: The installation procedure is very straightforward, but the setup can be a bit tricky. Installing GPG To add GPG to our Linux machine, we downloaded the appropriate archive file from www.gnupg.org, and used gunzip and tar to extract the files from the archive. To compile and install the program, use the same commands as for most Linux programs: configure (or ./configure depending on your system) make make install If you are not the root user, you will need to run the configure script with the prefix option as follows: ./configure prefix=/path/to/your/directory This is because a non-root user will not have access to the default directory for GPG. If all goes well, GPG will be compiled and the executable copied to /usr/local/bin/gpg or the directory that you specified. You can change many options. See the GPG documentation for details. Implementing Secure Transactions with PHP and MySQL C HAPTER 15 15 I MPLEMENTING S ECURE TRANSACTIONS 339 19 7842 CH15 3/6/01 3:40 PM Page 339 For a Windows server, the process is just as easy. Download the zip file, unzip it and place gpg.exe somewhere in your PATH. (C:\Windows\ or similar will be fine). Create a directory at C:\gnupg. Open a command prompt and type gpg. You also need to install GPG or PGP and generate a key pair on the system that you plan to check mail from. On the Web server, there are very few differences between the command-line versions of GPG and PGP, so we might as well use GPG as it is free. On the machine that you read mail from, you might prefer to buy a commercial version of PGP in order to have a nice graphical user interface plug-in to your mail reader. If you do not already have one, generate a key pair on your mail reading machine. Recall that a key pair consists of a Public Key that other people (and your PHP script) use to encrypt mail before sending it to you, and a Private Key, which you use to either decrypt received messages or sign outgoing mail. It is important that the key generation is done on your mail reading machine, rather than on your Web server, as your private key should not be stored on the Web server. If you are using the command-line version of GPG to generate your keys, enter the following command: gpg gen-key You will be asked a number of questions. Most of them have a default answer that can be accepted. You will be asked for a name and email address, which will be used to name the key. My key is named ‘Luke Welling <luke@tangledweb.com.au>’. I am sure that you can see the pattern. To export the public key from your new key pair, you can use the command: gpg export > filename This will give you a binary file suitable for importing into the GPG or PGP keyring on another machine. If you want to email this key to people, so they can import it into their key rings, you can instead create an ASCII version like this: gpg export -a > filename Having extracted the public key, you can upload the file to your account on the Web server. You can do this with FTP. The following commands assume that you are using UNIX. The steps are the same for Windows, but directory names and system commands will be different. E-commerce and Security P ART III 340 19 7842 CH15 3/6/01 3:40 PM Page 340 Log in to your account on the Web server and change the permissions on the file so that other users will be able to read it. Type chmod 644 filename You will need to create a keyring so that the user who your PHP scripts get executed as can use GPG. Which user this is depends on how your server is setup. It is often the user ‘nobody’, but could be something else. Change to being the Web server user. You will need to have root access to the server to do this. On many systems, the Web server runs as nobody. The following examples assume this. (You can change it to the appropriate user on your system.) If this is the case on your system, type su root su nobody Create a directory for nobody to store their key ring and other GPG configuration information in. This will need to be in nobody’s home directory. The home directory for each user is specified in /etc/passwd. On many Linux systems, nobody’s home directory defaults to /, which nobody will not have permission to write to. On many BSD systems, nobody’s home directory defaults to /nonexistent, which, as it doesn’t exist, cannot be written to. On our system, nobody has been assigned the home directory /tmp. You will need to make sure your Web server user has a home directory that they can write to. Type cd ~ mkdir .gnupg The user nobody will need a signing key of their own. To create this, run this command again: gpg gen-key As your nobody user probably receives very little personal email, you can create a signing only key for them. This key’s only purpose is to allow us to trust the public key we extracted earlier. To import the pubic key we exported earlier, use the following: gpg import filename To tell GPG that we want to trust this key, we need to edit the key’s properties using gpg edit-key ‘Luke Welling <luke@tangledweb.com.au>’ On this line, the text in quotes is the name of the key. Obviously, the name of your key will not be ‘Luke Welling <luke@tangledweb.com.au>’, but a combination of the name, comment, and email address you provided when generating it. Implementing Secure Transactions with PHP and MySQL C HAPTER 15 15 I MPLEMENTING S ECURE TRANSACTIONS 341 19 7842 CH15 3/6/01 3:40 PM Page 341 Options within this program include help, which will describe the available commands— trust, sign, and save. Type trust and tell GPG that you trust your key fully. Type sign to sign this public key using nobody’s private key. Finally, type save to exit this program, keeping your changes. Testing GPG GPG should now be set up and ready to use. Creating a file containing some text and saving it as test.txt will allow us to test it. Typing the following command gpg -a recipient ‘Luke Welling <luke@tangledweb.com.au>’ encrypt test.txt (modified to use the name of your key) should give you the warning gpg: Warning: using insecure memory! and create a file named test.txt.asc. If you open test.txt.asc you should see an encrypted message like this: BEGIN PGP MESSAGE Version: GnuPG v1.0.3 (GNU/Linux) Comment: For info see http://www.gnupg.org hQEOA0DU7hVGgdtnEAQAhr4HgR7xpIBsK9CiELQw85+k1QdQ+p/FzqL8tICrQ+B3 0GJTEehPUDErwqUw/uQLTds0r1oPSrIAZ7c6GVkh0YEVBj2MskT81IIBvdo95OyH K9PUCvg/rLxJ1kxe4Vp8QFET5E3FdII/ly8VP5gSTE7gAgm0SbFf3S91PqwMyTkD /2oJEvL6e3cP384s0i8lrBbDbOUAAhCjjXt2DX/uX9q6P18QW56UICUOn4DPaW1G /gnNZCkcVDgLcKfBjbkB/TCWWhpA7o7kX4CIcIh7KlIMHY4RKdnCWQf271oE+8i9 cJRSCMsFIoI6MMNRCQHY6p9bfxL2uE39IRJrQbe6xoEe0nkB0uTYxiL0TG+FrNrE tvBVMS0nsHu7HJey+oY4Z833pk5+MeVwYumJwlvHjdZxZmV6wz46GO2XGT17b28V wSBnWOoBHSZsPvkQXHTOq65EixP8y+YJvBN3z4pzdH0Xa+NpqbH7q3+xXmd30hDR +u7t6MxTLDbgC+NR =gfQu END PGP MESSAGE You should be able to transfer this file to the system where you generated the key initially and run: gpg -d test.txt.asc to see your original text again. To place the text in a file, rather than output it to the screen, you can use the -o flag and spec- ify an output file like this: gpg -do test.out test.txt.asc E-commerce and Security P ART III 342 19 7842 CH15 3/6/01 3:40 PM Page 342 If you have GPG set up so that the user your PHP scripts run as can use it from the command line, you are most of the way there. If this is not working, see your system administrator or the GPG documentation. Listings 15.1 and 15.2 enable people to send encrypted email by using PHP to call GPG. LISTING 15.1 private_mail.php—Our HTML Form to Send Encrypted Email <html> <body> <h1>Send Me Private Mail</h1> <? // you might need to change this line, if you do not use // the default ports, 80 for normal traffic and 443 for SSL if($HTTP_SERVER_VARS[“SERVER_PORT”]!=443) echo “<p><font color = red> WARNING: you have not connected to this page using SSL. Your message could be read by others.</font></p>”; ?> <form method = post action = send_private_mail.php><br> Your email address:<br> <input type = text name = from size = 38><br> Subject:<br> <input type = text name = title size = 38><br> Your message:<br> <textarea name = body cols = 30 rows = 10> </textarea><br> <input type = submit value = “Send!”> </form> </body> </html> LISTING 15.2 send_private_mail.php—Our PHP Script to Call GPG and Send Encrypted Email <? $to_email = “luke@localhost”; // Tell gpg where to find the key ring // On this system, user nobody’s home directory is /tmp/ putenv(“GNUPGHOME=/tmp/.gnupg”); Implementing Secure Transactions with PHP and MySQL C HAPTER 15 15 I MPLEMENTING S ECURE TRANSACTIONS 343 19 7842 CH15 3/6/01 3:40 PM Page 343 //create a unique file name $infile = tempnam(“”, “pgp”); $outfile = $infile.”.asc”; //write the user’s text to the file $fp = fopen($infile, “w”); fwrite($fp, $body); fclose($fp); //set up our command $command = “/usr/local/bin/gpg -a \\ recipient ‘Luke Welling <luke@tangledweb.com.au>’ \\ encrypt -o $outfile $infile”; // execute our gpg command system($command, $result); //delete the unencrypted temp file unlink($infile); if($result==0) { $fp = fopen($outfile, “r”); if(!$fp||filesize ($outfile)==0) { $result = -1; } else { //read the encrypted file $contents = fread ($fp, filesize ($outfile)); //delete the encrypted temp file unlink($outfile); mail($to_email, $title, $contents, “From: $from\n”); echo “<h1>Message Sent</h1> <p>Your message was encrypted and sent. <p>Thank you.”; } } if($result!=0) { echo “<h1>Error:</h1> E-commerce and Security P ART III 344 LISTING 15.2 Continued 19 7842 CH15 3/6/01 3:40 PM Page 344 . international PGP page: http://www.pgpi.org An Open Source alternative to PGP has recently become available. GPG—Gnu Privacy Guard—is a free (as in beer) and Free (as in speech) replacement for PGP. It. administrator or the GPG documentation. Listings 15.1 and 15.2 enable people to send encrypted email by using PHP to call GPG. LISTING 15.1 private_mail .php Our HTML Form to Send Encrypted Email <html> <body> <h1>Send. often need to write a MySQL password in a PHP script. Your PHP scripts are generally publicly loadable. This is not as much of a dis- aster as it might seem at first. Unless your Web server configuration