As IBM i shops expand their applications to the Internet, they're confronted with a variety of web server security concerns. Web server security has many facets, including firewalls, proxy servers, user authentication, file and directory protection, and SSL. This article focuses on user authentication and file and directory security for the IBM HTTP Server (Powered by Apache) shipped with IBM i. I start by summarizing the default configuration of an Apache server, move on to file and directory security, and finish with a few options for user authentication.
Apache configuration directives are placed in a file called httpd.conf. The "d" is for the word "daemon," and Apache is basically a daemon lying in wait for user requests across an Internet port. At its core, Apache is simply a file server that conforms to the Hypertext Transfer Protocol (HTTP). To create an HTTP server instance on IBM i, you could manually create an IFS directory, add a file called httpd.conf, and start the server with the Start TCP/IP Server (STRTCPSVR) command. You could also use IBM i's web-based HTTP Server Administration (HTTPAdmin) application, which Figure 1 shows. You start the HTTPAdmin application with the following Start TCP Server command:
STRTCPSVR *HTTP HTTPSVR(*ADMIN)
You can access the HTTPAdmin from your browser by using your IBM i's IP or domain and port 2001:
http://Your400sDomainOrIp:2001/HTTPAdmin
Creating an Apache Server
To create a web server instance with the HTTPAdmin app, perform the following steps:
- Click the Manage tab and then the HTTP Servers tab on the top menu panel.
- Click Create HTTP Server on the left menu.
- Enter a server name (I use penton for my example) and click Next.
- For the Server root prompt, accept the defaults (mine is /www/penton) and click Next.
- For the document root prompt, accept the defaults and click Next.
- For the IP addresses prompt, enter a port number greater than 2000—but one that
doesn't clash with existing servers at your company. (I used my zip code of 23238.) Click Next.
- For the access log prompt, accept the default of Yes and click Next. On the keep logs prompt, accept the automatic deletion at 7 days old and click Next.
- On the summary page, review your options and then click Finish.
Figure 2 shows the resultant httpd.conf file. The HTTPAdmin application creates the following directories:
/www/penton/conf
/www/penton/htdocs
/www/penton/logs
and the following files:
/www/penton/conf/httpd.conf
/www/penton/htdocs/index.html
Note that the name "penton" would be replaced with the name that you gave your server instance. You can start the server with
STRTCPSVR *HTTP HTTPSVR(penton)
You can test from your browser with
http://Your400sDomainOrIp:ThePortYouSelected/
If all goes well, the sample index.html page stored in the /www/penton/htdocs/ will be displayed.
Your next step will be to add web content and perhaps some kind of dynamic page generation by using RPG CGI, PHP, Java, or some other web language. And that's when your file, directory, and application security troubles begin.
Apache Directives
To thwart some of these security problems, we modify the httpd.conf file. But before we do that, let's review the default configuration. The Apache configuration file is comprised of directives. The directives used in Figure 2 include Listen, DocumentRoot, Options, LogFormat, CustomLog, LogMaint, SetEnvIf, and Directory. The table in Figure 3 describes the purpose of each of these directives.
The default configuration file is a little verbose, and you certainly can trim it down. Figure 4, for example, shows the httpd.conf file generated by a command from KrengelTech's RPG-XML Suite. The KrengelTech configuration file enables RPG CGI programs from its MYRXS library to be accessed through Apache. The configuration is relatively secure in that only RPG in the MYRXS library can be invoked, and no HTML content can be accessed. But you may want to enable other RPG libraries, and you may also want to enable static content.
To enable CGI RPG for other libraries, you add a ScriptAliasMatch and an Apache Directory directive. (Note that you can edit your httpd.conf file either from the HTTPAdmin web app or with the edit file command—or example: EDTF '/www/penton/conf/httpd.conf'.) The ScriptAliasMatch directive converts a concise, easy-to-key URL into a URL that qualifies an RPG file in the IFS. In the ScriptAliasMatch of Figure 4, any URL that has "MYRXS" in it matches the regular expression and will be converted into a qualified RPG URL. For example
http://Your400sDomainOrIp/MYRXS/simplecgi
would be converted to
http://Your400sDomainOrIp/QSYS.LIB/MYRXS.LIB/SIMPLECGI.PGM
If you wanted to enable CGI RPG from the SALES library, you could use the following:
ScriptAliasMatch:
ScriptAliasMatch ^/SAILZ/(.*) /qsys.lib/SALES.lib/$1.pgm
I misspelled SALES on purpose to show that the match string doesn't have to be the same as the library name. But adding that directive isn't good enough. The SALES library still needs to be authorized for access in the configuration. That's where the Directory directive comes in. You'd need to add the following:
<Directory /qsys.lib/SALES.lib>
options +ExecCGI
allow from all
order allow,deny
</Directory>
Note how the Options directive enabled CGI with +ExecCGI within the Directory directive. You could set that globally (as the default HTTP configuration file did in Figure 1), but the preceding strategy is more granular, which is always a good idea for security settings.
The Allow, Deny, and Order Apache directives are used to specify access specific to IP addresses and domain names. The word "all" refers to any domain or IP. But you could, for example allow only from the IP or domain of your whizbang-widgets―producing business partner:
Order deny,allow
Deny from all
Allow from widgetsRus.com
If you look at the default configuration in Figure 2, you'll see that the first Directory directive disallows any IP/domain on any directory. Then the second directive allows access specifically to /www/penton/htdocs. One last note about RPG CGI: For additional security, I would keep my RPG CGI for SALES application in a library called SALESWEB so there would be no way a non-CGI program could be invoked by a browser request.
One last step to enabling RPG for web access is to grant *USE privileges for the Apache CGI profile QTMHHTP1 to your RPG programs with the Edit Object Authority (EDTOBJAUT) command. Optionally you could enable *PUBLIC to have *USE access but setting authorities specific to the Apache profile is the more secure strategy.
File and Directory Authorities
Earlier, I said that the configuration file of Figure 4 disallows any static HTML content. To allow static content in your Apache document directory, you specify the following:
<Directory /www/penton/htdocs>
Order Allow,Deny
Allow From all
</Directory>
The problem is that, as you start plopping additional directories, HTML files, and so forth into the /www/penton/htdocs directory, you'll probably run into authorization errors. For example, when I added a directory called reports with an HTML file called lowInventory.html, my attempt at browser access garnered an error message: "Forbidden. You do not have permission to access /reports/lowInventory.html on this server." And the log file in /www/penton/logs showed:
[Sun Apr 19 14:58:47 2009] [error] [client 192.168.0.243] (3401)Permission denied.: ZSRV_MSG064B: access to /reports/lowInventory.html denied
To enable access, I needed to grant access to the directory and the file for the HTTP server's user profile: QTMHHTTP. One way to set authority is to use the Work with Object Links (WRKLNK) command, specifying the directory that contains the new subdirectories and files:
WRKLNK '/www/pendon/htdocs'
Then use option 9, Work with Authority, to add privileges for QTMHHTTP. Note that, for directories, QTMHHTTP needs *RX privileges. The R means read and the X is for execute but, in the context of a directory, it allows access (think axcess) to its content. To set authorities for all files in a directory, rather than manually selecting option 9 in the WRKLNK panel for each file, I suggest you use the Change Authority (CHGAUT) command and specify wildcard file names with an asterisk:
CHGAUT '/www/penton/htdocs/reports/*'
USER(QTMHHTTP) DTAAUT(*R) OBJAUT(*NONE)
It's a good idea to leave write privileges only to the folks adding content to the application. Note that if an IFS file is being accessed by RPG CGI, you will also have to authorize the Apache CGI profile, QTMHHTP1, to access those files and directories.
User Authentication
We've talked about how to enable RPG CGI and how to control directory- and file-level security. But if we're opening up dynamic information to the web, don't we also need to authenticate those users? Shouldn't we check to see whether they're authorized to access the information in that application? One way to do that is with application authentication. With application authentication, the prompting for user name and password is managed by the application. But application authentication requires a good bit of programming. And, for every user request, you need to check to see whether that user has successfully logged in. An easier solution is to use the authentication facilities provided with Apache: Basic Authentication. When you turn on Basic Authentication, when a user attempts to access a URL, Apache looks in the HTTP packet for a header called Authorization with a value of Basic and then a base64-encoded string, for example:
Authorization: Basic QwxhZGRpbjpvcGVuIHNlc2FtZQ==
If that header is unavailable or if the base64-encoded string contains no valid user name and password, Apache tells the browser, "Hey, this user must log in before I return the requested content." (Actually, to be more explicit, Apache returns an HTTP packet with a 401 error and the WWW-Authenticate header and the name of the application realm that requires authentication.) The browser then prompts the user for a name and password, as Figure 5 shows. For the remainder of the browser-to-server conversation, the browser continues to send the base64-encoded authorization HTTP header, and Apache allows access—no programming required.
One big caveat with Basic Authentication is that the base64-encoded user name and password can easily be decoded. But you can easily fix this problem by implementing SSL. SSL is something almost all business websites should be using anyway. That way, all browser requests and responses are encrypted.
Apache on IBM i has several methods for maintaining user names and passwords: IBM i user profiles, validation lists, and Lightweight Directory Access Protocol (LDAP) entries. In this article, I cover user profiles and validation lists. Setting up IBM i user profiles for authentication is easy. Within the Apache Directory directive that specifies the directory or CGI library that you want to require authentication for, add the following entries:
Require valid-user
PasswdFile %%SYSTEM%%
AuthType Basic
AuthName SomeAppRealmName
Of course, you'd replace SomeAppRealmName with a word that suggests the purpose of the application. Apache calls these authenticated areas realms. After you restart your application, the first time a user requests a resource (e.g., an HTML page or a CGI program), Apache tells the browser to prompt the user for a name and password.
Setting up IBM i―based Basic Authentication is easy. But doling out those profiles may be problematic, and letting those IBM i user profile names and passwords fly over the Internet may be a concern. Another option is validation lists. To add entries to validation lists by using the HTTPAdmin web application, click the Advanced tab, then click the Internet Users and Groups tab. Next click Add Internet User in the left menu, which Figure 6 shows. The validation list entry takes a library name and object name. Note that if the validation list doesn't exist when the Add Internet User page is applied, it will be created. An IBM i command to add entries would be nice to have, but there isn't one (although there are some APIs that let you code that interface yourself). Take note of the HTTPAdmin app's change, delete, and list menu options that let you maintain your validation list.
With validation lists available, your next step is to configure your httpd.conf file by placing the following in the appropriate Directory directive:
Order Allow,Deny
Allow From all
Require valid-user
PasswdFile denoncourt/validlist
UserID %%SERVER%%
AuthType Basic
AuthName SomeAppRealmName
Notice how the password file matches the one specified on the Add Internet User page.
Security Is Never Done
Unfortunately, in the world we live in, security concerns always remain. You now see how you can direct the daemon called Apache to be persnickety about who gets into which files and directories. But you should also configure it to communicate in code—specifically, SSL. As soon as you start sending any kind of private information across the web, SSL should be implemented. And you should work with a networking expert to set up a good firewall strategy.
Don Denoncourt is a System iNEWS technical editor and a trainer, mentor, and consultant for Java, Groovy, and Grails.