Top 10 security best practices for PHP

While developing a PHP web application, a web developer should also be concerned with security best practices. An insecure web application gives hackers the chance to steal valuable information, such as user data or credit card information. In addition, a data breach may have a drastic impact on the credibility and future operations of your organization.

To strengthen your defense mechanisms, this article lists 10 important security best practices for PHP applications. Let’s get started!

1. Update your PHP version regularly

As of July 9, 2020, the stable release for PHP is version 7.4.8. It’s important to regularly update your PHP version because newer versions often contain patches for known security issues. If you don’t update your PHP version to the latest stable release, hackers can exploit those known security vulnerabilities with older releases.

Furthermore, PHP lets you try out a preview release. Currently, this release is 8.0.0 Beta 2. However, security advisors discourage companies from engaging in testing preview releases because they can still contain unknown security flaws.

2. Beware of XSS attacks (Cross-site scripting)

An XSS attack, also known as cross-site scripting, refers to the unintended execution of remote code by your web application. For example, an XSS attack can occur when your web application accepts user input and prints it directly to the web page. Whenever a malicious user includes HTML, JavaScript, or even CSS, your web application will execute the remote code.

The example below includes a form that accepts user input.

<form action="form.php" method="post">
 <input type="text" name="message" value="">
 <input type="submit" name="submit" value="Submit message">
</form>

Next, we print the inputted data directly to the web page.

<?php
echo $_POST["message"];

Now, a malicious user can insert JavaScript like this. For example, the user can include a script tag with an alert function that your web application will execute.

<script>alert("Hacker was here")</script>

The above script tag will generate a simple alert message in the browser. This might not seem harmful. But a malicious user could easily steal sensitive user data or a user’s cookie.

What’s the Solution? To prevent a cross-site scripting attack, make sure to escape any user input to avoid the remote execution of code.

Want to learn more? Read this blog about reflected XSS attacks and how they affect your web application.

3. Use prepared SQL statements

A common mistake is to directly insert user input into an SQL statement. This leaves room for SQL injection attacks where the user can break the intended SQL query and execute any query they wish.

For example, the query below directly uses unsanitized user input inside the SQL query.

$users = mysql_query("SELECT * FROM `users` WHERE `id`='$_GET[id]'");

This gives a hacker the chance to break the statement and try to query for other information, such as all users’ data. With a prepared statement, the inputted values are escaped, leaving no room for an SQL injection attack.

Let’s take a look at the example below, which uses a prepared statement.

$stmt = $conn->prepare("INSERT INTO users (firstname, lastname) VALUES (?, ?)");
$stmt->bind_param("ss", $firstname, $lastname);

Note the first parameter of the bind_param function. This tells the SQL query the type of data you pass. Here, both the firstname and lastname parameters are of type String. This is an extra security measure to validate the data type of the input.

4. Don’t upload all framework files to your server

Many PHP frameworks consist of the Model-View-Controller file structure. This means that they come with a large file structure. For example, the PHP Slim Framework generates the following file structure.

public_html/
    .htaccess
    index.php
    styles/
    images/
    scripts/
app/
    routes/
        session.php
        member.php
        admin.php
vendor/
lib/
data/

It’s important that you don’t upload all of those files to your web server. Only upload the necessary web files that reside in the public_html folder.

Uploading all files to your server means that malicious users can access your files and inspect your business logic. This allows them to gain a deeper understanding of the application and possibly find security loopholes or bugs that they can exploit.

5. Always validate user input

When you always validate user input when you accept inputs through an input field, this ensures that every piece of data has the correct type and format.

Commonly, developers use regular expressions (regex) to validate data formats such as date of birth or phone number.

Let’s read the example below, which validates if the date of birth is in format YYYY-MM-DD.

$date="2012-09-12";

if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $date)) {
    return true;
} else {
    return false;
}

6. Limit directory access

The open_basedir function allows you to limit the files that PHP can access in your filesystem. If you set the open_basedir function to the root of your project, this means it can only access files in the root of your project and downward.

In case a malicious user gains access to your server via PHP and tries to access sensitive files such as /etc/passwd, the open_basedir function will prevent this.

7. Verify your SSL configuration

Every server should have an SSL certificate to securely transfer files via HTTPS. However, regularly check your server for outdated SSL certificates or weak ciphers.

Often, sysadmins forget to update SSL certificates when they expire. However, an SSL certificate helps your website to better defend against XSS attacks.

8. Use URL encoding

PHP gives developers the urlencode function to safely generate valid URLs. According to the PHP documentation, the function is convenient when encoding a string to be used in a query part of a URL.

Imagine that user input is used for generating a URL. In that case, you can use the urlencode function to generate a safe URL.

<?php
echo '<a href="mylink?user=', urlencode($userID), '">';
?>

9. Avoid remote file inclusion

Never accept user input for requiring a file. The example below shows a require statement that uses user-generated input and enables remote file inclusion.

<?php
$page = $_GET['location']
require($page . ".php");
?>

In this case, a user can input a malicious path such as ../../../etc/passwd and display the contents of the passwd file on a Linux/Unix server. Therefore, never accept user input for requiring a page. If you still want to accept user input for opening a file, make sure to validate the user input.

Furthermore, use best practice number 6 to limit directory access with the open_basedir function. A better solution would be to specify the possible choices using a switch statement.

For example, if the input matches home, you navigate the user to the homepage. See the example below, which illustrates a conditional switch for navigating the user. If the page doesn’t exist, we show an error page.

<?php
$page = $_POST['page'];
if ($page == "home") {
require("./pages/home.php");
} elseif ($page == "contact") {
require("./pages/contact.php");
} else {
require("./pages/error.php");
}
?>

10. Remember, documentation matters

Lastly, don’t forget to document your actions. Whenever you make changes to your server, update the version of your SSL certificate, or change a password, make sure to record those changes.

Other developers might find this information useful whenever they want to make changes to the server. It allows them to quickly check what happened recently. This way, you won’t come across unexpected surprises, such as a deprecated password for your MySQL server.

Furthermore, documentation is an ideal means of transferring knowledge. In case a developer leaves your company or gets sick, no knowledge is lost. That’s the primary purpose of documentation—transferring knowledge.

Summarizing PHP security

In the end, as a PHP developer, you’re responsible not only for implementing the required business logic but also for ensuring the security of it and of the code you’ve developed.

The key lesson from this article is to validate user input. Unvalidated user input often forms the basis of a security issue. Take a look at security issues such as remote file inclusion, URL encoding, or an XSS attack. All of them happen through invalidated user input.

Want to learn more about PHP security best practices? Make sure to check the PHP security manual and Sqreen’s PHP security checklist.

—-

This post was written by Michiel Mulders. Michiel is a passionate blockchain developer who loves writing technical content. Besides that, he loves learning about marketing, UX psychology, and entrepreneurship. When he’s not writing, he’s probably enjoying a Belgian beer!

Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
You May Also Like