Writing Secure PHP Applications
May 14, 2008 Hey, Pat:
My company has been playing around with PHP for a while. We are now designing real applications that we will deploy through our own Web server. What security ramifications do we need to consider in our design?
Thank you for your question.
Four aspects of PHP need to be considered to deal appropriately with security design in PHP applications:
The i5/OS PHP architecture consists of two Web server instances–the PHP core engine running in PASE, and i5/OS specific built-in functions i5_* and db2_*. The Web server instance that listens for requests from the network is the native i5/OS Apache Web server. It is configured to redirect all requests to a second Web server–an instance of the AIX-based Apache Web server running in PASE. The PASE Web server instance is configured to only accept requests from the localhost (programs running on the same system) on port 8000. In theory, users cannot talk directly to the PASE Apache Web server remotely. Note, however, that due to the way the proxy and reverse proxy Apache configuration attributes work, a user can access URLs representing directories served only by the PASE Apache Web server. Therefore proper security configuration of both Web servers is necessary!
The PHP install process performs the initial configuration of a bunch of stuff, including both Web servers. You can further tighten the configuration of these to limit their usage to only those PHP applications and the directories in which those application files exist. The goal is to prevent a knowledgeable user from using the Web server instances for PHP to point to any arbitrary directory on your system.
The external Web server instance receives a request and redirects the request to localhost:8000. The AIX-based Web server instance parses the request. PHP code is recognized and handled by the core PHP process running in AIX. This process runs under the i5/OS user profile named “nobody” that is created during the PHP install process.
PHP code can directly access i5/OS and DB2 resources by using the built-in i5_* and db2_* PHP functions. To use these functions, the PHP program must first call the “i5_connect()” or “db2_connect()” function. These functions, among other things, establish the user profile under which all other i5_ (or db2_ ) functions execute for that particular request. If the a userID and password are not provided on the i5_connect() function, the request runs under user profile “nobody.”
Normally, you should NEVER hardcode user IDs and passwords in an application. Therefore, you either do not supply a userID and password to the request or you need to get the userID and password to use through the Web page from the user. If you provide no userID and password, calls to subsequent i5_* (or db2_*) functions are performed under user profile “nobody.”
When getting data from users, which is handled by PASE-based applications, you have to follow coding practices that avoid buffer overflow flaws. This means you have to add code to perform a validity check on all of the data provided directly or indirectly by an end user (e.g., acceptable pathname and length, valid user ID name and length, valid password length, etc.). This is especially true for any data that is used as input for the i5_* and db2_* functions. Make sure the data is of a reasonable length and that you don’t blindly pass pointers to data without ensuring they are reasonably formatted including null terminators, etc.
The final aspect to consider is the object level access control methodology you use on your system. If you are like most customers, you probably have the default authority on your directories, libraries, and objects set to *CHANGE or higher. Now, when you consider there is no exit point for calls from the PHP engine running in PASE to native i5/OS resources, any user profile including “nobody” and the user ID provided by the user can access anything; exit point programs cannot detect or prevent this. This is another reason why I believe an exclusionary access control model (default authority to sensitive data, libraries, programs is set to *EXCLUDE, relying on adopted authority wherever possible and a limited amount of private authorities when absolutely necessary).
For those IFS directories containing PHP programs, exclude PUBLIC, and grant private *X authority to profiles under which the Web server is running and to the “nobody” user profile. Grant private *R authority to stream files in those directories.
To protect i5/OS libraries and objects, you also need PUBLIC *EXCLUDE and private *USE/*CHANGE as required by the PHP applications and the i5/OS applications that use those libraries and objects. Note that “private” authority includes private authority for user profiles and/or groups directly to the library or object or to an authorization list that protects that particular library or object.
In short, running PHP applications securely requires you to:
Pat Botz is vice president of security consulting at Group 8 Security. He has over 25 years of experience in the computer industry, including the UNIX, AS/400, and System i markets. He spent nine years as a member, team leader, and lead architect for IBM’s OS/400 and i5/OS security team. Pat has been a speaker at numerous industry events including COMMON and the IBM Tech Conferences and is a co-author of the book, “Experts’ Guide to OS400 and i5/OS Security.”