The problem with PHP is that it has no security architecture. What do I mean by security architecture? A single pervasive vision for security, which will last for approximately five years with little or no design maintenance. A robust security architecture creates a balance between functionality and risk, and ensures that by default, simple activities and normal features create as little risk as possible.
There is no point in a “safe” mode which prohibits most scripts of any consequence. For example, safe mode prevents most gallery applications from running. This wouldn’t be a bad thing if you’re a gallery hating hoster who wanted to prevent such apps from running, but this is not the case 99 times out of a 100. What is worse though, is that safe mode is trivially worked around if you want to completely 0wn the host using an attack script, but hard to work around if all you want to do is save some images to disk. The new security architecture must make balanced choices which allow apps to do their stuff, but not allow attack scripts to do their stuff.
PHP has had several disjunct goes at implementing “security” features, but unfortunately, failed to implement them correctly. All these efforts requires modern safer programs to include code which tests if these options are enabled, and if so, to then undo their handiwork. Often such code is buggy and slow. For example, many hosters (incorrectly) have register globals enabled as many customer scripts “need” them. However, safer PHP scripts do not need register globals as they follow the usual OWASP model of validate! validate! validate! from the correct source ($_GET, $_POST, etc). So they have to undo the registered globals, requiring even more work and slowing each and every script down. If they get it wrong (and often they do; some programs actually look to see if register globals if off and put the old bad behavior back!) All this is wasted work.
One of the key findings of the major sources of PHP vulnerability relate to many distinct configuration flavors. Hosters often run insecurely to maximize compatibility, and with “register globals”/”magic quotes” and “safe mode”, apps have at least 8 common combos which may or may not work for them. This makes testing significant PHP apps basically impossible. The new security architecture must provide a single correct configuration which programs can rely on, so there is no reason to enable these unsafe features. This also means that it is easy for auditors and reviewers to find code which relies on unsafe features, and even easier to find code which relies on the new security architecture so they can concentrate on the really dodgy stuff – bad design and silly processes.
The pervasive security architecture explicitly reduces attack surface area of any PHP 6.0 script to manageable levels, and controls all security features in a cohesive and orthagonal way. A key goal is to ensure that existing scripts will not need to be modified (but also do not benefit … unless it is easy and safe to do so), but new applications which are aware of PHP 6.0 will automatically get the safest programming experience.
Of course, it is possible to write insecure programs in any language if you try hard enough. What I want is the easiest way is also the safest way.
Security Architecture Objectives
The major objectives for the PHP Security Architecture are:
- By default, the new architecture uses a low attack surface area approach, disabling any features which have a security outcome
- The easiest way to do something, is also the safest way
- If we can provide security without coding, then that will happen (think freebie XSS protection)
- Backward compatibility is not broken, but hosters and admins are free to enable this mode (yes, by default unless you ask for the new architecture, the old scripts will not run)
- Unsafe constructs and patterns, like mysql_query() which cannot be made safe at any price, do not run in the new architecture. At all.
- Safe constructs, like PDO are unchanged and require no porting
- The basic architecture pattern is “deny unless permitted” as it applies to operating system and network resources
- Never introduce another broken security idea into the new security architecture. ie, no more “register globals” or “magic quotes”. Either the new feature is the lowest risk way of achieving an outcome, or it is not introduced. This will require significant peer review.
Compliant scripts invoke the new security architecture, but once invoked the entire script must be compatible with the new architecture. The new security architecture has to be wholistic and apply to all functions. But as this is a lot of work, the initial effort has to be to secure the securable, and remove access to the unsecurable.
Bad security patterns in need of solving
There is no point in fixing broken API, so I will not delve into straight security “fixes” for existing PHP applications. However, I have reviewed the top five PHP related issues and worked out their root causes.
The five things are:
- File inclusion attacks, usually resulting in remote command injection
- Remote command injection
- Validation failures, particularly XSS attacks
- File system attacks
- and lastly, configuration related attacks which makes the attack so much worse
Creating secure patterns and fixing APIs which remove these issues permanently will advise the security architecture’s overall look and feel, and it will help us create “safer” PHP-like constructs. There is no point in producing Java-like or .NET like constructs on top of PHP – PHP developers use PHP for a reason: it’s a pretty simple language to pick up and fast to make things happen.That is not to say that there will be no J2EE or .NET influences, particularly if one of those does something very well, and PHP currently does not have an equivalent API. For example, if we need a new API for feature X already present in another platform, then there is little reason to create an API with tiny detail differences. All that means is that programmers moving from other platforms to PHP need to learn the PHP nuances, but the more likely instance is that they will get it wrong and there will be subtle bugs. A typical example is that in .NET, structured exception handling is pervasive, whereas in PHP, we use PHP’s loose typing to return bools, occasionally -1, occasionally throw an exception and sometimes a string. We should be careful about return results like this, particularly if we pick up an API wholesale from somewhere else.
The sandbox as it stands in the runkit is insufficient. What we need is isolation so that each application has a level of isolation from the underlying environment, and other applications. Hosters often run hundreds of users on each host and many applications may exist in each account, such as a CMS, blog and gallery … just as I do here. All are in PHP. The apps can see and change each other’s resources like config and temporary files, which is not an ideal situation.
Obviously, some apps require less isolation than others, and some require tight integration (a CMS and an integrated forum software for example), so a model must exist which allows such integration without opening up an entire full trust model as today.
Bringing old features into the fold
There is no point in creating a massive new API just for security architecture, but there needs to be a way to identify those areas which are affected. Luckily, a great deal of the API is already in PHP, so it’s “just” a matter of securing the boundary in the core between PHP applications and the underlying operating system.
However there are gaps in PHP requiring new API and ideas to allow basic security activities
- The idea of an intrinsic authorization model which code can rely upon to be there
- Privilege levels / trust model, running as the lowest possibile privilege and allowing impersonation and elevation of privilege without secret storage
- Secret storage and other crypto API, particularly as it relates to database connections
- Implementing encrypted connections to databases and LDAP stores by default unless unencrypted is required
Conclusion… for now
There is much work to do. I will blog my thoughts here regularly and refine the overall approach. I will obviously find some hidden corners of PHP of which I am currently completely unaware, so I will take advice from anyone who has experience in these areas.