I recently installed PHP on Ubuntu 24.04.3 LTS and discovered that the default PHP configuration in php.ini
prioritizes compatibility over security. While I appreciate the focus on maintaining compatibility, I don’t need it for a clean installation – I’d rather maximize security from the start.
Restricting file access with open_basedir
First, I set open_basedir
to /var/www:/tmp
.
By default, PHP scripts can access any file on the server that the PHP process has permissions for. This creates a major risk if a malicious script runs, as it could reach sensitive system files. Setting open_basedir
limits PHP’s file operations to specific directories: /var/www
for web content and /tmp
for temporary files.
This restriction minimizes damage from an attacker, even if they exploit a vulnerability in your application.
Disabling allow_url_fopen
Next, I disabled allow_url_fopen
.
When enabled, allow_url_fopen
lets PHP treat URLs (like http://
or ftp://
) as files, allowing functions such as file_get_contents()
to fetch remote content. While useful, this can be abused to include malicious remote scripts or data, potentially leading to remote code execution or data leaks.
Disabling it prevents PHP from accessing remote resources as files, lowering the risk of remote file inclusion attacks.
Enabling strict session management
I also enabled session.use_strict_mode
.
By default, PHP accepts any session ID sent by a client, which lets attackers force a known session ID and potentially hijack sessions. Enabling session.use_strict_mode
ensures PHP only accepts server-generated session IDs, rejecting uninitialized or invalid ones.
This bolsters session security by thwarting session fixation attacks, where an attacker tricks a user into using a pre-set session ID.
Securing session cookies
Finally, I enabled these settings:
session.cookie_secure
: Ensures session cookies are sent only over HTTPS, preventing interception on unsecured networks.session.cookie_httponly
: Blocks client-side scripts (like JavaScript) from accessing session cookies, reducing the risk of session theft through cross-site scripting (XSS) attacks.session.cookie_samesite
: Adds theSameSite
attribute to cookies, helping prevent cross-site request forgery (CSRF) attacks by controlling when cookies are sent in cross-origin requests.
Together, these enhance session cookie security, safeguarding user sessions from interception, theft, or exploitation in various scenarios.
The tradeoff between compatibility and security
Compatibility and security often clash. Empathetic engineers aim to preserve compatibility for users, but that can hinder security improvements.
A prime example is Java’s object serialization, which can enable arbitrary code execution during deserialization of untrusted data. Serialization is core to Java’s API and ingrained in many legacy enterprise applications. Altering or removing it would disrupt countless systems.
Escape hatches
Both security and compatibility are valuable, so how do we reconcile them? In the Jenkins project, our approach is to be secure by default but offer an escape hatch for compatibility.
An “escape hatch” is a command-line option that lets users opt into the old, insecure (but compatible) behavior. In Jenkins, we use a documented set of Java system properties to achieve this.
When we introduce an incompatible security enhancement in Jenkins, we usually provide an escape hatch to revert to the prior behavior. This gives temporary relief to users who upgrade and face compatibility issues. They can then migrate to the secure alternative at their own pace and eventually drop the escape hatch. New installations start with the secure defaults.
Conclusion
Security and compatibility can conflict, but escape hatches provide the best of both worlds: new setups are secure by default, while existing ones have a path to get relief from breaking changes.