Home > Backend Development > PHP Tutorial > That strange PHP code in frameworks and CMS

That strange PHP code in frameworks and CMS

Barbara Streisand
Release: 2024-11-12 07:56:02
Original
726 people have browsed it

Ese extraño código PHP en frameworks y CMS

Note: to follow this post it is assumed that you have minimal programming knowledge in PHP.

This post is about a fragment of PHP code that you may have seen at the top of your favorite CMS or framework and which you have probably read that you should always include, for security, in the header of all the PHP files you develop, although without a very clear explanation of why. I am referring to this code:

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}
Copy after login
Copy after login
Copy after login
Copy after login

This type of code is very common in WordPress files, although it actually appears in almost all frameworks and CMS. In the case of the CMS Joomla, for example, the only thing that changes is that, instead of ABSPATH, JEXEC is used. Otherwise, the logic is the same. This CMS arose from another one called Mambo, which also used similar code, but with _VALID_MOS as a constant. If we go back even further in time, we will find that the first CMS to use this type of code was PHP-Nuke (considered by some to be the first CMS in PHP).

The execution flow of PHP-Nuke (and most CMS and frameworks today) consisted of sequentially loading several files that, together, responded to the action performed by the user or visitor on the web. That is, imagine a website from that time, under the domain example.net and with this CMS installed. Every time the home page loaded, the system executed a sequence of files in an orderly manner (in this case it is just an example, not a real sequence): index.php => load_modules.php => modules.php. That is, in this sequence, index.php was loaded first, then this script loaded load_modules.php, and this in turn modules.php.

This execution chain did not always start with the first file (index.php). In fact, anyone could skip part of this flow by directly calling one of the other PHP files by its URL (e.g. http://example.net/load_modules.php or http://example.net/modules.php) , which, as we will see, could be dangerous in many cases.

How was this problem resolved? A security measure was introduced, adding codes to the beginning of each file, similar to this:

<?php

if (!eregi("modules.php", $HTTP_SERVER_VARS['PHP_SELF'])) {
    die ("You can't access this file directly...");
}
Copy after login
Copy after login

Basically, this code, located in the header of a file called modules.php, checked to see if modules.php was being accessed directly via the URL. If so, the execution was stopped, displaying the message: "You can't access this file directly...". If $HTTP_SERVER_VARS['PHP_SELF'] did not contain modules.php, then it meant that we were in the normal flow of execution and were allowed to continue.

This code, however, had some limitations. First, the code was different for each file it was inserted into, which added complexity. Additionally, in certain circumstances, PHP did not assign a value to $HTTP_SERVER_VARS['PHP_SELF'], which limited its effectiveness.

So what did the developers do? They replaced all those code fragments with a simpler and more efficient version:

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}
Copy after login
Copy after login
Copy after login
Copy after login

In this new code, which was already quite common in the PHP community, the existence of a constant was verified. This constant was defined and assigned a value in the first file of the flow (index.php or home.php or some similar file). Therefore, if this constant did not exist in some other file in the stream, it meant that someone had skipped the index.php file and was trying to access another file directly.

Dangers of someone launching a PHP file directly

Surely at this point you are thinking that breaking the chain of execution must be the most serious thing in the world. However, the reality is that, normally, it does not represent a significant danger.

Danger can arise when a PHP error exposes the path to our files. This should not worry us if we have error suppression configured on the server, and, even if the errors were not hidden, the exposed information would be minimal, providing just a few clues to a possible attacker.

It could also happen that someone accesses files that contain fragments of HTML (from views), revealing part of their content. In most cases, this should not be a cause for concern either.

Finally, it could happen that a developer, either due to inattention or lack of experience, inserts dangerous code without external dependency in the middle of an execution flow. This is very unusual, since normally the code of a framework or CMS depends on other classes, functions or external variables for its execution. Therefore, if you try to run a script directly through the URL, it will fail to find these dependencies and will not continue execution.

So why add the constant code if there is hardly any cause for concern? The reason is this: "This method also prevents accidental variable injection via an attack on register globals, preventing the PHP file from assuming it is inside the application when it really is not."

Register globals

Since the beginning of PHP, all variables sent through URLs (GET) or forms (POST) were automatically converted to global. That is, if the file download.php?filepath=/etc/passwd was accessed, in the download.php file (and in those that depended on it in the execution flow) echo $filepath could be used; and the result would be /etc/passwd.

Within download.php, there was no way to tell if the $filepath variable had been created by a previous file in the execution flow or if someone had spoofed it via the URL or with a POST. This generated large security holes. Let's see it with an example, assuming that the download.php file contains the following code:

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}
Copy after login
Copy after login
Copy after login
Copy after login

The developer probably thought about implementing his code with a Front Controller pattern, that is, making all web requests go through a single input file (index.php, home.php, etc.). This file would be responsible for initializing the session, loading common variables, and finally, redirecting the request to a specific script (in this case download.php) to download the file.

However, an attacker could bypass the planned execution sequence by simply calling download.php?filepath=/etc/passwd as mentioned before. Thus, PHP would automatically create the global variable $filepath with the value /etc/passwd, allowing the attacker to download that file from the system. Serious mistake.

This is just the tip of the iceberg, as even more dangerous attacks could be carried out with minimal effort. For example, in code like the following, which the programmer could have left as an unfinished script:

<?php

if (!eregi("modules.php", $HTTP_SERVER_VARS['PHP_SELF'])) {
    die ("You can't access this file directly...");
}
Copy after login
Copy after login

An attacker could execute any code using a Remote File Inclusion (RFI) attack. Thus, if the attacker created a My.class.php file on his own site https://mysite.net with any code he wanted to execute, he could call the vulnerable script by passing it his domain: codigo_inutil.php?base_path=https:// mysite.net, and the attack was completed.

Another example: in a script called remove_file.inc.php with the following code:

<?php

if (!defined('MODULE_FILE')) {
    die ("You can't access this file directly...");
}
Copy after login

an attacker could call this file directly using a URL like remove_file.inc.php?filename=/etc/hosts, and thus attempt to delete the /etc/hosts file from the system (if the system allows it, or other files to which you have delete permissions).

In a CMS like WordPress, which also uses global variables internally, this type of attack was devastating. However, thanks to the constant technique, these and other PHP scripts were protected. Let's see it with the last example:

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}
Copy after login
Copy after login
Copy after login
Copy after login

Now, if someone tried to access remove_file.inc.php?filename=/etc/hosts, the constant would block access. It is essential that it be a constant, because if it were a variable, of course, the attacker could inject it.

At this point you're probably wondering why PHP kept this functionality if it was so dangerous. Also, if you know other scripting languages ​​(JSP, Ruby, etc.), you will see that they do not have something similar (which is why they do not use the constant technique either). Let us remember that PHP was born as a template system in C, and this behavior facilitated development. The good news is that, seeing the problems it caused, PHP maintainers decided to introduce a directive in php.ini called register_globals (activated by default) to allow disabling this functionality.

But since the problems persisted, they disabled it by default. Even so, many hosts continued to enable it for fear that their clients' projects would stop working, since much of the code at that time did not use the recommended HTTP_*_VARS variables to access the GET/POST/... values, but rather global variables.

Finally, seeing that the situation did not change, they made a drastic decision: eliminate this functionality in PHP 5.4 to avoid all these problems. Thus, nowadays, scripts like the ones we have seen (without using constants) no longer normally pose a danger, except for some harmless warning/notice in certain cases.

use today

Today, the constant technique is still common. However, what is sad—and the reason that led to this post—is that few developers know the real reason for its use.

As with other good practices of the past (such as copying parameters in a function to local variables to avoid dangers with references in the call, or using underscores in private variables to distinguish them), many still apply it just because someone once told them that it was a good practice, without considering whether it really adds value in current times. The reality is that, in the majority of cases, this technique is no longer necessary.

Some reasons why this practice has lost relevance are as follows:

  • Disappearance of *register globals: Since PHP 5.4, the functionality of registering GET and POST variables as PHP global variables no longer exists. As we have seen, without *register globals, the execution of individual scripts becomes harmless, eliminating the main reason for this practice.

  • Better design in current code: Even in versions prior to PHP 5.4, modern code is better designed, structured in classes and functions, which complicates access or manipulation through variables external. Even WordPress, which often uses global variables, minimizes these risks.

  • Use of *front-controllers: Nowadays, most web applications use well-designed *front-controllers, which ensure that the code of the Classes and functions will only be executed if the execution chain starts at the main entry point. So it doesn't matter if someone tries to upload files in isolation: the logic will not activate if the flow is not started from the right point.

  • Class autoloading: Since class autoloading is used in current development, the use of include or require has been greatly reduced. This means that, unless you are a novice developer, there should be no includes or requires that could present risks (such as Remote File Inclusion or Local File Inclusion).

  • Separation of public and private code: In many modern CMS and frameworks, public code (such as assets) is separated from private code (programming code). This measure is especially valuable as it ensures that if PHP fails on the server, the code in the PHP files (whether or not they use the constant technique) is not exposed. Although this was not specifically implemented to mitigate register globals, it helps avoid other security issues.

  • Extended use of friendly URLs: Nowadays, it is common to configure the server to use friendly URLs, which always forces a single entry point to programming. This makes it almost impossible for anyone to upload PHP files in isolation.

  • Suppressing error output in production: Most modern CMS and frameworks block error output by default, so attackers can't find clues about the internal workings of the application, something that could facilitate other types of attacks.

Although this technique is no longer necessary in the majority of cases, this does not mean that it is never useful. As a professional developer, it is essential to analyze each case and decide if the constant technique is relevant in the specific context in which you are working. This is a criterion that you should always apply, even in what you consider good practices.

Doubts? Here are some tips

If you are still not sure when to apply the constant technique, these recommendations can guide you:

  • Always use the technique if you think your code can run on a version of PHP earlier than 5.4.
  • Do not use it if the file only contains the definition of a class.
  • Do not use it if the file contains only functions.
  • Do not use if the file only includes HTML/CSS, unless the HTML exposes some type of valuable information.
  • Do not use it if the file only contains constants.

For everything else, if you have doubts, apply it. In most cases it should not be harmful and could protect you in unexpected circumstances, especially if you are just starting out. With time and experience, you will be able to better evaluate when to apply this and other techniques.

Ese extraño código PHP en frameworks y CMS

Keep learning...

  • register_globals - MediaWiki
  • PHP: Using Register Globals - Manual
  • Remote file inclusion vulnerabilities [LWN.net]
  • Bugtraq: Serious security hole in Mambo Site Server version 3.0.X

The above is the detailed content of That strange PHP code in frameworks and CMS. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template