322 Chapter 15 Implementing Secure Transactions with PHP and MySQL Figure 15.4 SSL breaks up, compresses, hashes, and encrypts data before sending it. 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 future, SSL 3.0 may 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 con- tains improvements intended to overcome weaknesses of SSL. 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 system 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. 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 525x ch15 1/24/03 3:41 PM Page 322 323 Providing Secure Storage n 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 database.You can use the stripslashes() function to return the data to its original form. n Magic quotes.You can switch on the magic_quotes_gpc and magic_quotes_run- time directives in your php.ini file.These directives will automatically add and strip slashes for you.The magic_quotes_gpc directive will apply this formatting to incoming GET, POST, and cookie variables, and the magic_quote_runtime direc- tive will apply it to data going to and from databases. n 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 metacharac- ters that can be used to force your system to run arbitrary commands entered by a malicious user. n 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. n 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 sep- arately 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 cor- rectly 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 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. 19 525x ch15 1/24/03 3:41 PM Page 323 324 Chapter 15 Implementing Secure Transactions with PHP and MySQL 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 pro- gram to decrypt data, and one or more key files. If the cracker can read your data, proba- bly 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 disaster as it might seem at first. Unless your Web server configuration is bro- ken, 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 interpreter, 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 direc- tories, 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 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 spe- cial 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 with- out storing it at all. 19 525x ch15 1/24/03 3:41 PM Page 324 325 Using Encryption in PHP 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 defacto 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. 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 command line tools it might not matter, but each has different interfaces such as plug-ins for 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 somebody 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 available 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. Depending on whether you choose the .tar.gz or .tar.bz2 archive, you will need to use gunzip and tar or to extract the files from the archive. 19 525x ch15 1/24/03 3:41 PM Page 325 326 Chapter 15 Implementing Secure Transactions with PHP and MySQL To compile and install the program, use the same commands as for most Linux pro- grams: 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. For a Windows server, the process is even easier. 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 ver- sions 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 nicer 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 Yo u will be asked a number of questions. Most of them have a default answer that can be accepted. On separate lines, you will be asked for your real name, your email address and a comment, 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. Had I provided a comment too, it would be between the name and address. To export the public key from your new key pair, you can use the command: gpg export > filename 19 525x ch15 1/24/03 3:41 PM Page 326 . 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 Yo u will be asked a number of. write a MySQL password in a PHP script.Your PHP scripts are generally publicly loadable.This is not as much of a disaster as it might seem at first. Unless your Web server configuration is bro- ken,. to use gunzip and tar or to extract the files from the archive. 19 525x ch15 1/24/03 3:41 PM Page 325 326 Chapter 15 Implementing Secure Transactions with PHP and MySQL To compile and install the