The code in Listing 14.4 acts in a very similar way to the previous listings in this chapter. If the user has not yet provided authentication information, it will be requested. If she has pro- vided incorrect information, she is given a rejection message. If she provides a matching name- password pair, she is presented with the contents of the page. The user will see an interface somewhat different from the previous listings. We are not pro- viding an HTML form for login information. The user’s browser will present her with a dialog box. Some people see this as an improvement; others would prefer to have complete control over the visual aspects of the interface. The login dialog box that Internet Explorer provides is shown in Figure 14.4. Implementing Authentication with PHP and MySQL C HAPTER 14 14 IMPLEMENTING AUTHENTICATION 315 FIGURE 14.4 The user’s browser is responsible for the appearance of the dialog box when using HTTP authentication. Because the authentication is being assisted by features built in to the browser, the browsers choose to exercise some discretion in how failed authorization attempts are handled. Internet Explorer lets the user try to authenticate three times before displaying the rejection page. Netscape Navigator will let the user try an unlimited number of times, popping up a dialog box to ask, “Authorization failed. Retry?” between attempts. Netscape only displays the rejection page if the user clicks Cancel. As with the code given in Listing 14.1 and 14.2, we could include this code in pages we wanted to protect, or automatically prepend it to every file in a directory. 18 7842 CH14 3/6/01 3:35 PM Page 315 Using Basic Authentication with Apache’s .htaccess Files We can achieve very similar results to the previous script without writing a PHP script. The Apache Web server contains a number of different authentication modules that can be used to decide the validity of data entered by a user. The easiest to use is mod_auth, which compares name-password pairs to lines in a text file on the server. In order to get the same output as the previous script, we need to create two separate HTML files, one for the content and one for the rejection page. We skipped some HTML elements in the previous examples, but really should include <html> and <body> tags when we are generat- ing HTML. Listing 14.5 contains the content that authorized users see. We have called this file content.html. Listing 14.6 contains the rejection page. We have called this rejection.html. Having a page to show in case of errors is optional, but it is a nice, professional touch if you put something useful on it. Given that this page will be shown when a user attempts to enter a protected area but is rejected, useful content might include instructions on how to register for a password, or how to get a password reset and emailed if it has been forgotten. LISTING 14.5 content.html—Our Sample Content <html><body> <h1>Here it is!</h1> <p>I bet you are glad you can see this secret page. </body></html> LISTING 14.6 rejection.html—Our Sample 401 Error Page <html><body> <h1>Go Away!</h1> <p>You are not authorized to view this resource. </body></html> There is nothing new in these files. The interesting file for this example is Listing 14.6. This file needs to be called .htaccess, and will control accesses to files and any subdirectories in its directory. E-commerce and Security P ART III 316 18 7842 CH14 3/6/01 3:35 PM Page 316 LISTING 14.7 .htaccess—An .htaccess File Can Set Many Apache Configuration Settings, Including Activating Authentication ErrorDocument 401 /chapter14/rejection.html AuthUserFile /home/book/.htpass AuthGroupFile /dev/null AuthName “Realm-Name” AuthType Basic require valid-user Listing 14.7 is an .htaccess file to turn on basic authentication in a directory. Many settings can be made in an .htaccess file, but the six lines in our example all relate to authentication. The first line ErrorDocument 401 /chapter14/rejection.html tells Apache what document to display for visitors who fail to authenticate. You can use other ErrorDocument directives to provide your own pages for other HTTP errors such as 404. The syntax is ErrorDocument error_number URL For a page to handle error 401, it is important that the URL given is publicly available. It would not very useful in providing a customized error page to tell people that their authoriza- tion failed if the page is locked in a directory in which they need to successfully authenticate to see. The line AuthUserFile /home/book/.htpass tells Apache where to find the file that contains authorized users’ passwords. This is often named .htpass, but you can give it any name you prefer. It is not important what this file is called, but it is important where it is stored. It should not be stored within the Web tree— somewhere that people can download it via the Web server. Our sample .htpass file is shown in Listing 14.8. As well as specifying individual users who are authorized, it is possible to specify that only authorized users who fall into specific groups may access resources. We have chosen not to, so the line AuthGroupFile /dev/null sets our AuthGroupFile to point to /dev/null, a special file on UNIX systems that is guaran- teed to be null. Implementing Authentication with PHP and MySQL C HAPTER 14 14 IMPLEMENTING AUTHENTICATION 317 18 7842 CH14 3/6/01 3:35 PM Page 317 Like the PHP example, to use HTTP authentication, we need to name our realm as follows: AuthName “Realm-Name” You can choose any realm name you prefer, but bear in mind that the name will be shown to your visitors. To make it obvious that the name in the example should be changed, ours is named “Realm-Name”. Because a number of different authentication methods are supported, we need to specify which authentication method we are using. We are using Basic authentication as specified by this directive: AuthType Basic We need to specify who is allowed access. We could specify particular users, particular groups, or as we have done, simply allow any authenticated user access. The line require valid-user specifies that any valid user is to be allowed access. LISTING 14.8 .htpass—The Password File Stores Usernames and Each User’s Encrypted Password user1:0nRp9M80GS7zM user2:nC13sOTOhp.ow user3:yjQMCPWjXFTzU user4:LOmlMEi/hAme2 Each line in the .htpass file contains a username, a colon, and that user’s encrypted password. The exact contents of your .htpass file will vary. To create it, you use a small program called htpasswd that comes in the Apache distribution. The htpasswd program is used in one of the following ways: htpasswd [-cmdps] passwordfile username or htpasswd -b[cmdps] passwordfile username password The only switch that you need to use is -c. Using -c tells htpasswd to create the file. You must use this for the first user you add. Be careful not to use it for other users because if the file exists, htpasswd will delete it and create a new one. E-commerce and Security P ART III 318 18 7842 CH14 3/6/01 3:35 PM Page 318 The optional m, d, p, or s switches can be used if you want to specify which encryption algo- rithm (including no encryption) you would like to use. The b switch tells the program to expect the password as a parameter, rather than prompting for it. This is useful if you want to call htpasswd noninteractively as part of a batch process, but should not be used if you are calling htpasswd from the command line. The following commands created the file shown in Listing 14.8: htpasswd -bc /home/book/.htpass user1 pass1 htpasswd -b /home/book/.htpass user2 pass2 htpasswd -b /home/book/.htpass user4 pass3 htpasswd -b /home/book/.htpass user4 pass4 This sort of authentication is easy to set up, but there are a few problems with using an .htaccess file this way. Users and passwords are stored in a text file. Each time a browser requests a file that is pro- tected by the .htaccess file, the server must parse the .htaccess file, and then parse the pass- word file, attempting to match the username and password. Rather than using an .htaccess file, we could specify the same things in our httpd.conf file—the main configuration file for the Web server. An .htaccess file is parsed every time a file is requested. The httpd.conf file is only parsed when the server is initially started. This will be faster, but means that if we want to make changes, we need to stop and restart the server. Regardless of where we store the server directives, the password file still needs to be searched for every request. This means that, like other techniques we have looked at that use a flat file, this would not be appropriate for hundreds or thousands of users. Using Basic Authentication with IIS Like Apache, IIS supports HTTP authentication. Apache uses the UNIX approach and is con- trolled by editing text files, and as you might expect, selecting options in dialog boxes controls the IIS setup. Using Windows 2000, you change the configuration of Internet Information Server 5 (IIS5) using the Internet Services Manager. You can find this utility by choosing Administrative Tools in the Control Panel. The Internet Services Manager will look something like the picture shown in Figure 14.5. The tree control on the left side shows that on the machine named windows-server, we are running a number of services. The one we are interested in is the default Web site. Within this Web site, we have a directory called protected. Inside this directory is a file called content.html. Implementing Authentication with PHP and MySQL C HAPTER 14 14 IMPLEMENTING AUTHENTICATION 319 18 7842 CH14 3/6/01 3:35 PM Page 319 FIGURE 14.5 The Microsoft Management Console allows us to configure Internet Information Server 5. To add basic authentication to the protected directory, right-click on it and select Properties from the context menu. The Properties dialog allows us to change many settings for this directory. The two tabs that we are interested in are Directory Security and Custom Errors. One of the options on the Directory Security tab is Anonymous Access and Authentication Control. Pressing this Edit button will bring up the dialog box shown in Figure 14.6. E-commerce and Security P ART III 320 FIGURE 14.6 IIS5 allows anonymous access by default, but allows us to turn on authentication. Within this dialog, we can disable anonymous access and turn on basic authentication. With the settings shown in Figure 14.6, only people who provide an appropriate name and password can view files in this directory. 18 7842 CH14 3/6/01 3:35 PM Page 320 In order to duplicate the behavior of the previous examples, we will also provide a page to tell users that their authentication details were not correct. Closing the Authentication methods dia- log box will allow us to choose the Custom Errors tab. The Custom Errors tab, shown in Figure 14.7, associates errors with error messages. Here, we have stored the same rejection file we used earlier, rejection.html, shown in Listing 14.6. IIS gives us the ability to provide a more specific error message than Apache does, providing the HTTP error code that occurred and a reason why it occurred. For the error 401, which repre- sents failed authentication, IIS provides five different reasons. We could provide different mes- sages for each, but have chosen to only replace the two that are going to occur in this example with our rejection page. Implementing Authentication with PHP and MySQL C HAPTER 14 14 IMPLEMENTING AUTHENTICATION 321 FIGURE 14.7 The Custom Errors tab lets us associate custom error pages with error events. That is all we need to do to require authentication for this directory using IIS5. Like a lot of Windows software, it is easier to set up than similar UNIX software, but harder to copy from machine to machine or directory to directory. It is also easy to accidentally set it up in a way that makes your machine insecure. The major flaw with IIS’s approach is that it authenticates Web users by comparing their login details to accounts on the machine. If we want to allow a user “john” to log in with the pass- word “password”, we need to create a user account on the machine, or on a domain, with this name and password. You need to be very careful when you are creating accounts for Web authentication so that the users only have the account rights they need to view Web pages and do not have other rights such as Telnet access. 18 7842 CH14 3/6/01 3:35 PM Page 321 Using mod_auth_mysql Authentication As already mentioned, using mod_auth with Apache is easy to set up and is effective. Because it stores users in a text file, it is not really practical for busy sites with large numbers of users. Fortunately, you can have most of the ease of mod_auth, and the speed of a database using mod_auth_mysql. This module works in much the same way as mod_auth, but because it uses a MySQL database instead of a text file, it can search large user lists quickly. In order to use it, you will need to compile and install the module on your system or ask your system administrator to install it. Installing mod_auth_mysql In order to use mod_auth_mysql, you will need to set up Apache and MySQL according to the instruction in Appendix A, “Installing PHP and MySQL,” but add a few extra steps. There are quite good instructions in the files README and USAGE that are in the distribution, but here is a summary. 1. Obtain the distribution archive for the module. It is on the CD-ROM that came with this book, but you can always get the latest version from http://www.zend.com or alternatively http://www.mysql.com/downloads/contrib.html 2. Unzip and untar the source code. 3. Change to the mod_auth_mysql directory and run configure. You need to tell it where to find your MySQL installation and your Apache source code. To suit the directory struc- ture on my machine, I typed ./configure with-mysql=/var/mysql with-apache=/src/apache_1.3.12 but your locations might be different. 4. Run make, and then make install. You will need to add activate-module=src/modules/auth_mysql/libauth_mysql.a to the parameters you give to configure when you configure Apache. For the setup on my system, I used ./configure enable-module=ssl \ activate-module=src/modules/php4/libphp4.a \ enable-module=php4 prefix=/usr/local/apache enable-shared=ssl \ activate-module=src/modules/auth_mysql/libauth_mysql.a E-commerce and Security P ART III 322 18 7842 CH14 3/6/01 3:35 PM Page 322 5. After following the other steps in Appendix A, you will need to create a database and table in MySQL to contain authentication information. This does not need to be a sepa- rate database or table; you can use an existing table such as the auth database from the example earlier in this chapter. 6. Add a line to your httpd.conf file to give mod_auth_mysql the parameters it needs to connect to MySQL. The directive will look like Auth_MySQL_Info hostname user password Did It Work? The easiest way to check whether your compilation worked is to see whether Apache will start. To start Apache, type /usr/local/apache/bin/apachectl startssl If it starts with the Auth_MySQL_Info directive in the httpd.conf file, mod_auth_mysql was successfully added. Using mod_auth_mysql After you have successfully installed the module, using it is no harder than using mod_auth. Listing 14.9 shows a sample .htaccess file that will authenticate users with encrypted pass- words stored in the database created earlier in this chapter. LISTING 14.9 .htaccess—This .htaccess File Authenticates Users Against a MySQL Database ErrorDocument 401 /chapter14/rejection.html AuthName “Realm Name” AuthType Basic Auth_MySQL_DB auth Auth_MySQL_Encryption_Types MySQL Auth_MySQL_Password_Table auth Auth_MySQL_Username_Field name Auth_MySQL_Password_Field pass require valid-user You can see that much of Listing 14.9 is the same as Listing 14.7. We are still specifying an error document to display in the case of error 401 (when authentication fails). We again Implementing Authentication with PHP and MySQL C HAPTER 14 14 IMPLEMENTING AUTHENTICATION 323 18 7842 CH14 3/6/01 3:35 PM Page 323 specify basic authentication and give a realm name. As in Listing 14.7, we will allow any valid, authenticated user access. Because we are using mod_auth_mysql and did not want to use all the default settings, we have some directives to specify how this should work. Auth_MySQL_DB, Auth_MySQL_Password_ Table, Auth_MySQL_Username_Field, and Auth_MySQL_Password_Field specify the name of the database, the table, the username field, and the password field, respectively. We are including the directive Auth_MySQL_Encryption_Types to specify that we want to use MySQL password encryption. Acceptable values are Plaintext, Crypt_DES, or MySQL. Crypt_DES is the default, and uses standard UNIX DES–encrypted passwords. From the user perspective, this mod_auth_mysql example will work in exactly the same way as the mod_auth example. She will be presented with a dialog box by her Web browser. If she successfully authenticates, she will be shown the content. If she fails, she will be given our error page. For many Web sites, mod_auth_mysql is ideal. It is fast, relatively easy to implement, and allows you to use any convenient mechanism to add database entries for new users. For more flexibility, and the ability to apply fine-grained control to parts of pages, you might want to implement your own authentication using PHP and MySQL. Creating Your Own Custom Authentication We have looked at creating our own authentication methods including some flaws and compro- mises and using built-in authentication methods, which are less flexible than writing your own code. Later in the book, when we have covered session control, you will be able to write your own custom authentication with fewer compromises than in this chapter. In Chapter 20, we will develop a simple user authentication system that avoids some of the problems we have faced here by using sessions to track variables between pages. In Chapter 24, we apply this approach to a real-world project and see how it can be used to implement a fine-grained authentication system. Further Reading The details of HTTP authentication are specified by RFC 2617, which is available at http://www.rfc-editor.org/rfc/rfc2617.txt The documentation for mod_auth, which controls basic authentication in Apache, can be found at http://www.apache.org/docs/mod/mod_auth.html E-commerce and Security P ART III 324 18 7842 CH14 3/6/01 3:35 PM Page 324 . Listing 14.8: htpasswd -bc /home/book/.htpass user1 pass1 htpasswd -b /home/book/.htpass user2 pass2 htpasswd -b /home/book/.htpass user4 pass3 htpasswd -b /home/book/.htpass user4 pass4 This sort. enable-module =php4 prefix=/usr/local/apache enable-shared=ssl activate-module=src/modules/auth _mysql/ libauth _mysql. a E-commerce and Security P ART III 322 18 7842 CH14 3/6/01 3 :35 PM Page 322 5 14.6, only people who provide an appropriate name and password can view files in this directory. 18 7842 CH14 3/6/01 3 :35 PM Page 320 In order to duplicate the behavior of the previous examples, we