PHP 8.2 and WoltLab: The SensitiveParameter Attribute

Public Domain Image by the US Government

Every modern software consists in part of reusable software libraries to provide functionality, and WoltLab Suite is no exception. The use of such software libraries avoids reinventing the wheel by outsourcing certain, often complex, tasks to the library, which has been developed by experts in the respective field and also has a proven track record through frequent use in practice.

The majority of software libraries used by WoltLab Suite - just like WoltLab Suite Core, the core of our own software - are free software. They are provided free of charge by the respective developers under an open source license. The use of open source libraries allows us to understand the library in detail and also to correct any errors ourselves. Errors in our software that are caused by the use of a software library are, from the customer’s point of view, still an error in our software that must be corrected by ourselves.

When it comes to correcting errors in deployed libraries, however, we follow a very liberal “upstreaming policy”: we submit fixes and also new functions to the original library whenever possible. This benefits all parties involved: It removes some burden from the developers of the library and at the same time we benefit from the fact that our use case is known to the developer and can be taken into account in a future development.

We have already made such fixes and improvements to various libraries, but not to PHP itself - until now. PHP 8.2 includes two improvements developed by WoltLab: A major new feature and a minor improvement.

“Redacting Parameters in Back Traces”

The problem

Whenever a serious error occurs in our software, the well-known “An error has occurred” error page appears. Depending on the settings, this error page also contains the so-called stack trace, which, in simple terms, describes the path that the software took during execution until it encountered the error. This stack trace also contains the parameters that were passed to the called functions and they provide important information for diagnosing the cause. For this reason, when reporting errors, it is important to always provide the complete error message, including the stack trace, so that this information is available.

Under certain circumstances, however, the stack trace data may also contain sensitive information such as passwords. For example, establishing a connection to the database requires the database password to be transmitted. If the connection cannot be established, for example because the database server is temporarily unavailable, then the generated stack trace would usually also contain the password in plain text as a parameter.

To protect sensitive data in the stack trace, WoltLab Suite has therefore included a sanitization mechanism since early versions to clean up the stack trace. This allowed us to ensure that passwords for databases are removed from the stack trace before they were logged or displayed. We extended this cleanup over time to include parameters that – based on naming – might contain sensitive data.

By its nature, such a heuristic cannot reliably detect all possible occurrences and thus suffers from the “false negatives” phenomenon. Conversely, it is also affected by “false positives”: Parameters are mistakenly identified as sensitive and filtered out. We were determined to get to the root of the problem and develop a solution directly integrated into PHP to reliably protect not only our software, but also other software based on PHP, and in this way improve the security of the ecosystem as a whole.

The “RFC” process for submitting changes to PHP

The development of the PHP programming language and the integration of new functions is carried out via the so-called “RFC process”. An RFC is a document that precisely describes the proposed functionality. Unlike a simple “wish” for a new feature, an RFC details all aspects and implications of the proposed change so that the reader can get a full picture of the proposal.

Via the mailing list for the development of PHP (the so-called “PHP Internals” list), the RFC is presented and discussed with other developers in order to resolve any problems or ambiguities. Once the discussion phase is complete, the RFC goes into the voting phase and must be accepted by a 2/3 majority for it to be incorporated into PHP. Voting is open to core PHP developers who are actively driving PHP development, as well as experienced developers who have been actively participating in discussions about new RFCs for some time.

For the implementation we decided to use the attributes introduced with PHP 8.0, with which it is possible to store additional data for classes, functions and even parameters:

PHP
function checkPassword(
    string $username,
    #[\SensitiveParameter] // Marks the '$password' parameter with the information 'SensitiveParameter'
    string $password,
): bool {
  // …
}

Before we then described this concept in the form of the RFC document, we first programmed the necessary adjustments to PHP in order to test the concept and check whether such a change is technically feasible in the first place. Fortunately, this was the case, so we subsequently wrote the RFC “Redacting Parameters in back traces” (backtrace is an alternative name for stack trace) and posted it for discussion on the Internals mailing list in early January 2022. As part of the discussion, we were also invited by Derick Rethans to talk about the RFC on the PHP Internals News podcast, allowing us to explain the background of our proposal in more detail.

During the discussion we also added the ability to explicitly access the original value of redacted parameters if needed; instead of removing the values completely, they are wrapped in a kind of “protective envelope” (a class called SensitiveParameterValue). This “secure by default” approach ensures that no sensitive data is visible during normal stack trace processing, but allows it to still be queried by the software itself if needed.

With this change, we released the RFC for voting in early February and were able to report two weeks later that our proposed improvement was accepted for integration into PHP 8.2 with 96% approval. Starting in April, we added the new attribute to the functions directly integrated in PHP for sensitive parameters in a second step, so that every user of PHP from version 8.2 onwards benefits from basic protection of sensitive data. Later in the year, the new attribute was also integrated by various PHP software libraries in their own code to protect users of these libraries as well.

WoltLab Suite 6.0, which is currently under development, has also already been adapted to enable the best possible integration of our RFC. Our stack trace cleanup feature also takes the new attribute into account in older PHP versions to provide the best possible protection for our customers. Also, the heuristic for detecting sensitive parameters is still applied if not all external libraries have been adapted yet.

We have visually reworked the display of error messages to make sensitive parameters more recognizable in the stack trace. For security reasons, the removed data is neither included in the display nor in the error log.


An error message informing about a failed database connection. Sensitive information has been redacted.

Conclusion

We were quite familiar with the concept of the RFC process for advancing PHP before the first RFC of our own, but without having gone through it ourselves, the process seemed very impressive, as you have to find consensus among many developers with a wide variety of knowledge, experience and opinions. Nevertheless, the integration of our proposal was a success across the board and we were able to make PHP a little bit better for everyone as a result.

In fact, it was so successful that we spontaneously submitted a second, less extensive RFC (Make the iterator_*() family accept all iterables) to PHP in July, which was also accepted. We also participated in the discussion of other developers' RFCs on the Internals mailing list, so that our own requirements and wishes would be taken into account.

We can recommend every PHP developer to follow the discussions on the Internals mailing list, to participate actively and possibly to write their own RFC - your own wishes and opinions can only be taken into account if you express them.

The development of PHP 8.2 has come to a close with the feature freeze in July and the release a few days ago. However, we will continue to participate in the development of PHP in the future and write new RFCs as needed.