{"id":11179,"date":"2024-10-30T12:20:03","date_gmt":"2024-10-30T11:20:03","guid":{"rendered":"https:\/\/www.vaadata.com\/blog\/?p=11179"},"modified":"2024-10-30T12:20:06","modified_gmt":"2024-10-30T11:20:06","slug":"php-security-best-practices-vulnerabilities-and-attacks","status":"publish","type":"post","link":"https:\/\/www.vaadata.com\/blog\/php-security-best-practices-vulnerabilities-and-attacks\/","title":{"rendered":"PHP Security Best Practices, Vulnerabilities and Attacks"},"content":{"rendered":"\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"722\" height=\"350\" src=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2024\/10\/php-security-best-practices.png\" alt=\"\" class=\"wp-image-11180\" srcset=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2024\/10\/php-security-best-practices.png 722w, https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2024\/10\/php-security-best-practices-300x145.png 300w\" sizes=\"(max-width: 722px) 100vw, 722px\" \/><\/figure>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p><strong>PHP <\/strong>remains the most popular server-side programming language. Used by over <a href=\"https:\/\/w3techs.com\/technologies\/history_overview\/programming_language\" target=\"_blank\" rel=\"noopener\" title=\"\">75% of the world&#8217;s applications<\/a>, PHP is now in version 8. This version, like its predecessors, always brings new features and additional layers of security.<\/p>\n\n\n\n<p>However, PHP&#8217;s security is built on its historical features. In this article, we will review the best practices for securing your PHP applications. In particular, we will look at common vulnerabilities and attacks, as well as configuration flaws that can compromise the security of your PHP applications.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Comprehensive Guide to PHP Security Best Practices<\/h2>\n\n\n<div class=\"wp-block-aioseo-table-of-contents\"><ul><li><a class=\"aioseo-toc-item\" href=\"#reduce-the-attack-surface-of-your-php-applications\">Reduce the Attack Surface of your PHP Applications<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#monitor-php-configurations-and-updates\">Monitor PHP configurations and updates<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#configure-error-reports-appropriately\">Configure error reports appropriately<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#apply-the-principles-of-security-through-obscurity\">Apply the principles of security through obscurity<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#preventing-sql-injections\">Preventing SQL Injections<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#use-prepared-statements\">Use Prepared Statements<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#validate-and-sanitise-user-input\">Validate and sanitise user input<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#protecting-against-command-injections\">Protecting Against Command Injections<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#disable-dangerous-functions-with-disable_functions\">Disable dangerous functions with disable_functions<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#strictly-validate-input-parameters\">Strictly validate input parameters<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#escape-commands-and-arguments-using-the-appropriate-functions\">Escape commands and arguments using the appropriate functions<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#preventing-session-hijacking\">Preventing Session Hijacking<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#do-not-accept-session-identifiers-in-urls\">Do not accept session identifiers in URLs<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#secure-session-cookies-with-the-httponly-and-secure-flags\">Secure session cookies with the HttpOnly and Secure flags<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#strengthen-the-entropy-of-session-identifiers\">Strengthen the entropy of session identifiers<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#regenerate-session-identifiers-during-critical-actions\">Regenerate session identifiers during critical actions<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#add-additional-security-measures-defence-in-depth\">Add additional security measures (defence in depth)<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#countering-xss-attacks\">Countering XSS Attacks<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#filter-inputs-and-escape-outputs\">Filter inputs and escape outputs<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#strengthening-protection-with-http-headers\">Strengthening protection with HTTP headers<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#cookies-protection\">Cookies protection<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#securing-file-uploads\">Securing File Uploads<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#restrict-access-to-authenticated-users\">Restrict access to authenticated users<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#restrict-the-extensions-and-formats-accepted\">Restrict the extensions and formats accepted<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#configure-an-htaccess-file-to-restrict-access-to-uploaded-files\">Configure an .htaccess file to restrict access to uploaded files<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#validate-the-mime-type-and-file-extension\">Validate the MIME type and file extension<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#manage-files-securely-when-saving-them\">Manage files securely when saving them<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#limit-file-size-with-upload_max_filesize\">Limit file size with upload_max_filesize<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#protecting-against-csrf-cross-site-request-forgery-attacks\">Protecting Against CSRF (Cross Site Request Forgery) Attacks<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#use-post-requests-for-sensitive-actions\">Use POST requests for sensitive actions<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#implement-csrf-tokens-in-forms\">Implement CSRF tokens in forms<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#use-anti-csrf-libraries-or-frameworks\">Use anti-CSRF libraries or frameworks<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#conclusion\">Conclusion<\/a><\/li><\/ul><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"reduce-the-attack-surface-of-your-php-applications\">Reduce the Attack Surface of your PHP Applications<\/h2>\n\n\n\n<p>Reducing the attack surface of a web application involves minimising vulnerable entry points, by limiting the elements that can be exploited by attackers.<\/p>\n\n\n\n<p>This includes rigorous configuration management, regular updates, error handling, source code protection and security through obscurity.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-69a03039b2b2f9ca8866ab8f18848da2\" id=\"monitor-php-configurations-and-updates\" style=\"color:#c0b800\">Monitor PHP configurations and updates<\/h3>\n\n\n\n<p>One of the most crucial aspects of security is knowing your web server&#8217;s components and configuration.<\/p>\n\n\n\n<p>Here are some essential questions to ask yourself:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>What version of PHP is installed?<\/li>\n\n\n\n<li>Which libraries are used?<\/li>\n\n\n\n<li>What external code is included, and is it reliable?<\/li>\n\n\n\n<li>Which framework is used, and what version is it?<\/li>\n\n\n\n<li>Is the operating system up to date?<\/li>\n<\/ul>\n\n\n\n<p>If you can&#8217;t answer these questions clearly and precisely, you&#8217;re missing information that is essential for the security of your application.<\/p>\n\n\n\n<p>It is crucial to have a <strong>centralised, up-to-date list of the components of<\/strong> your infrastructure. This enables you to answer two key questions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Do I really need this component?<\/strong> If not, it should be deleted. Any unused component represents a useless attack surface.<\/li>\n\n\n\n<li><strong>How do I know if an update is available for this component?<\/strong> It is essential to have processes in place to track updates, via mailing lists, notifications, etc.<\/li>\n<\/ul>\n\n\n\n<p><strong>Security configuration must be a continuous process<\/strong>. This may seem obvious at the start of a project, but after several months in production, this task is often neglected.<\/p>\n\n\n\n<p>So it&#8217;s essential to check your configurations and updates regularly to limit the risks.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-80d9efd961ed0d8fb0ea04c86589f65e\" id=\"configure-error-reports-appropriately\" style=\"color:#c0b800\">Configure error reports appropriately<\/h3>\n\n\n\n<p>Errors displayed are valuable for development. However, they can also expose sensitive information when visible in production. It is therefore essential to configure error reports appropriately.<\/p>\n\n\n\n<p>Here are three important parameters in the<strong> php.ini<\/strong> file<strong>:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>error_reporting<\/strong>: controls which types of error are reported.<\/li>\n\n\n\n<li><strong>display_errors<\/strong>: defines whether errors should be displayed on screen.<\/li>\n\n\n\n<li><strong>log_errors<\/strong>: enables errors to be logged in a log file.<\/li>\n<\/ul>\n\n\n\n<p>On a development environment, it is acceptable to display errors on screen, but in production, this must be strictly forbidden.<\/p>\n\n\n\n<p>Instead, enable error logging and choose the types of error to be logged carefully, particularly on high-traffic sites where logs can become voluminous.<\/p>\n\n\n\n<p>The <code>error_reporting<\/code> parameter can be configured as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>error_reporting = E_ALL &amp; ~E_NOTICE &amp; ~E_DEPRECATED &amp; ~E_STRICT<\/code><\/pre>\n\n\n\n<p>In production, you can set <code>display_errors<\/code> to \u2018Off\u2019 and <code>log_errors<\/code> to \u2018On\u2019 for a better balance between security and debugging.<\/p>\n\n\n\n<p><a href=\"https:\/\/www.php.net\/manual\/en\/errorfunc.configuration.php#ini.error-reporting\" target=\"_blank\" rel=\"noopener\" title=\"\">Find out more about configuring error reports.<\/a><\/p>\n\n\n\n<p>Other security parameters in <strong>php.ini<\/strong> should be reviewed regularly, such as :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>disable_functions<\/strong>: disables certain potentially dangerous functions.<\/li>\n\n\n\n<li><strong>memory_limit<\/strong>: limits the amount of memory a script can use.<\/li>\n\n\n\n<li><strong>max_execution_time<\/strong>: prevents scripts from running indefinitely.<\/li>\n\n\n\n<li><strong>file_uploads<\/strong> and <strong>upload_max_filesize<\/strong>: control file upload authorisations and limits.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-9b3c0d2e2e1dc29fc0541cd221961f48\" id=\"apply-the-principles-of-security-through-obscurity\" style=\"color:#c0b800\">Apply the principles of security through obscurity<\/h3>\n\n\n\n<p>Although security through obscurity is not a complete strategy in itself, it can slow down attackers and make their task more difficult.<\/p>\n\n\n\n<p>For example:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Hide PHP version<\/strong>: prevents attackers from knowing the exact version of PHP being used. This can be done by disabling <code>expose_php<\/code> in the php.ini file: <code>expose_php = Off<\/code>.<\/li>\n\n\n\n<li><strong>Generic login error messages<\/strong>: when a connection attempt fails, do not specify whether it is the password or the user name that is incorrect. Use a generic message such as \u2018Incorrect identifiers\u2019 to avoid revealing that a valid identifier has been found.<\/li>\n<\/ul>\n\n\n\n<p>These techniques do not replace fundamental security measures, but they do make it harder for attackers to gather exploitable information.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"preventing-sql-injections\">Preventing SQL Injections<\/h2>\n\n\n\n<p><a href=\"https:\/\/www.vaadata.com\/blog\/sql-injections-principles-impacts-exploitations-security-best-practices\/\" target=\"_blank\" rel=\"noopener\" title=\"\">SQL injections<\/a> are dangerous attacks that can seriously compromise the security of your PHP application. Fortunately, you can protect yourself by following a few simple best practices.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-dff011d2694c870db72836947063f698\" id=\"use-prepared-statements\" style=\"color:#c0b800\">Use Prepared Statements<\/h3>\n\n\n\n<p>The most effective way of preventing SQL injections is to use Prepared statements, available via <a href=\"https:\/\/www.php.net\/manual\/en\/pdo.prepared-statements.php\" target=\"_blank\" rel=\"noopener\" title=\"\">PHP&#8217;s PDO extension<\/a>. <\/p>\n\n\n\n<p>Prepared statements separate the structure of the SQL query from the data passed to it, thus preventing the execution of malicious SQL code.<br>Here is an example of an implementation using PDO:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$pdo = new PDO('mysql:host=localhost;dbname=test', $user, $password);\n$stmt = $pdo->prepare('SELECT * FROM users WHERE username = :username');\n$stmt->bindParam(':username', $username);\n$stmt->execute();<\/code><\/pre>\n\n\n\n<p>The parameters sent in the request are treated as data, and not as code, thus blocking any attempt at malicious injection.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-39082ddd3dc0079a0843524d66619f26\" id=\"validate-and-sanitise-user-input\" style=\"color:#c0b800\">Validate and sanitise user input<\/h3>\n\n\n\n<p>Even with prepared statements, it is important to validate and sanitise user input. Use functions tailored to your needs to check the type and format of data before using it in an SQL query.<\/p>\n\n\n\n<p>This includes using PHP filters such as <code>filter_var()<\/code> to validate email addresses or integers.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"protecting-against-command-injections\">Protecting Against Command Injections<\/h2>\n\n\n\n<p>Executing commands via PHP can be extremely powerful, but it also presents a high risk if precautions are not taken. <\/p>\n\n\n\n<p>Poor management can allow attackers to <a href=\"https:\/\/www.vaadata.com\/blog\/what-is-command-injection-exploitations-and-security-best-practices\/\" target=\"_blank\" rel=\"noopener\" title=\"\">inject malicious commands<\/a> into your server, compromising the security of your application.<\/p>\n\n\n\n<p>Here are the best practices to follow.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-0197f555a3c04325f9a05348bdce0e8e\" id=\"disable-dangerous-functions-with-disable_functions\" style=\"color:#c0b800\">Disable dangerous functions with disable_functions<\/h3>\n\n\n\n<p>The first step in limiting the risk of command injection is to disable potentially dangerous PHP functions.<\/p>\n\n\n\n<p>This can be done via the <code>disable_functions<\/code> directive in the <strong>php.ini<\/strong> file. Once these functions are disabled, they cannot be exploited, even by an attacker who manages to inject PHP code via another security flaw.<\/p>\n\n\n\n<p>Here is an example configuration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>disable_functions = show_source, exec, shell_exec, system, passthru, proc_open, popen, curl_exec, curl_multi_exec, parse_ini_file, show_source<\/code><\/pre>\n\n\n\n<p>These functions are commonly used to execute system commands, open processes or access sensitive information. Disabling them prevents misuse in the event of a breach.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-7dccca44fb415bc9257b34a22aece6da\" id=\"strictly-validate-input-parameters\" style=\"color:#c0b800\">Strictly validate input parameters<\/h3>\n\n\n\n<p>If you absolutely must use command execution functions (such as <code>exec()<\/code> or <code>system()<\/code>), you must be extremely careful about the parameters passed to them.<\/p>\n\n\n\n<p>Validate all input data using whitelists, i.e. accepting only pre-approved values. This reduces the likelihood of malicious input being executed as a command.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-a20ff649a8bbbefc6aac92660a94f14c\" id=\"escape-commands-and-arguments-using-the-appropriate-functions\" style=\"color:#c0b800\">Escape commands and arguments using the appropriate functions<\/h3>\n\n\n\n<p>When executing commands, it is essential to escape arguments correctly to avoid injection attempts.<\/p>\n\n\n\n<p>PHP provides native functions to secure command execution.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>escapeshellcmd()<\/strong>: Escapes special characters in a command to prevent them from being interpreted as shell operators. Use this function to secure the entire command.<\/li>\n\n\n\n<li><strong>escapeshellarg()<\/strong>: Escapes arguments passed to a command to treat them as literal strings. This prevents the injection of special characters or additional commands.<\/li>\n<\/ul>\n\n\n\n<p>These functions prevent malicious users from injecting additional commands or modifying the executed command via malformed inputs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"preventing-session-hijacking\">Preventing Session Hijacking<\/h2>\n\n\n\n<p>Session hijacking is often based on exploiting session identifiers to gain access to a legitimate user&#8217;s session. <\/p>\n\n\n\n<p>A common attack is session fixation, where the attacker forces the victim to use a session identifier known to the attacker, only to exploit that session once the victim has logged in.<\/p>\n\n\n\n<p>To prevent this type of attack, it is essential to follow a several best practices.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-af02d2350178076bc8c4a893f503e5a9\" id=\"do-not-accept-session-identifiers-in-urls\" style=\"color:#c0b800\">Do not accept session identifiers in URLs<\/h3>\n\n\n\n<p>The use of session identifiers in URLs makes it easier for attackers to capture or reuse this information, particularly through Man in the Middle attacks.<\/p>\n\n\n\n<p>To avoid this, configure PHP to only accept session identifiers via cookies. This can be enabled by setting the <code>session.use_only_cookies<\/code> parameter in the php.ini file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>session.use_only_cookies = 1<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-140a435fe28ee64c30812d8bd1ed31cb\" id=\"secure-session-cookies-with-the-httponly-and-secure-flags\" style=\"color:#c0b800\">Secure session cookies with the HttpOnly and Secure flags<\/h3>\n\n\n\n<p>Session cookies must be protected against attacks such as <strong>cross-site scripting (XSS)<\/strong>.<\/p>\n\n\n\n<p>Two important measures to take :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>HttpOnly flag<\/strong>: Prevents access to cookies via JavaScript, thereby limiting the risks associated with XSS vulnerabilities.<\/li>\n\n\n\n<li><strong>Secure flag<\/strong>: Ensures that cookies are only sent via secure connections (HTTPS).<\/li>\n<\/ul>\n\n\n\n<p>These parameters can be activated in the php.ini file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>session.cookie_httponly = 1\nsession.cookie_secure = 1<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-bf2b8a7fa163b752efcc90958027c332\" id=\"strengthen-the-entropy-of-session-identifiers\" style=\"color:#c0b800\">Strengthen the entropy of session identifiers<\/h3>\n\n\n\n<p>The session identifiers generated must be sufficiently complex to make them difficult to predict. By increasing the entropy of identifiers, you reduce the risk of <a href=\"https:\/\/www.vaadata.com\/blog\/brute-force-attacks-principles-and-security-best-practices\/\" target=\"_blank\" rel=\"noopener\" title=\"\">brute force attacks<\/a>.<\/p>\n\n\n\n<p>On Linux systems, we recommend using the special <code>\/dev\/urandom<\/code> file to generate session identifiers with a high level of entropy:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>session.entropy_file = \/dev\/urandom<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-da01ac6090e9857865a47774dcb5e9a1\" id=\"regenerate-session-identifiers-during-critical-actions\" style=\"color:#c0b800\">Regenerate session identifiers during critical actions<\/h3>\n\n\n\n<p>A crucial measure to limit session fixation attacks is to regenerate the session identifier when the user performs a sensitive action, such as logging in.<\/p>\n\n\n\n<p>This prevents an attacker from exploiting a fixed session before the user has authenticated.<\/p>\n\n\n\n<p>PHP provides a simple function for regenerating the session ID:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>session_regenerate_id(true); \/\/ true to delete the old session ID<\/code><\/pre>\n\n\n\n<p>It is advisable to regenerate the identifier at critical moments, such as :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>After the user logs in.<\/li>\n\n\n\n<li>When changing privileges or accessing sensitive information.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-b782b855971fb893b75d18e5a29f04a3\" id=\"add-additional-security-measures-defence-in-depth\" style=\"color:#c0b800\">Add additional security measures (defence in depth)<\/h3>\n\n\n\n<p>To further strengthen the security of your sessions, several complementary strategies can be put in place:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Monitor user activity<\/strong>: Record important actions carried out in each user&#8217;s session. For example, you can keep a record of recent interactions to detect suspicious behaviour, such as attempts to access sensitive resources without consistent prior action.<\/li>\n\n\n\n<li><strong>Check the \u2018User-Agent<\/strong>\u2018: Store the user&#8217;s <strong>User-Agent<\/strong> (browser fingerprint) in the session, then compare it when sensitive actions are taken. If the browser fingerprint suddenly changes, this could indicate a session takeover. Below is an example of implementation:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>if (!isset($_SESSION&#91;'user_agent'])) {\n    $_SESSION&#91;'user_agent'] = $_SERVER&#91;'HTTP_USER_AGENT'];\n} elseif ($_SESSION&#91;'user_agent'] !== $_SERVER&#91;'HTTP_USER_AGENT']) {\n    die(\"User-Agent mismatch. Possible session hijacking attempt.\");\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"countering-xss-attacks\">Countering XSS Attacks<\/h2>\n\n\n\n<p>Protecting your PHP application against <a href=\"https:\/\/www.vaadata.com\/blog\/xss-cross-site-scripting-vulnerabilities-principles-types-of-attacks-exploitations-and-security-best-practices\/\" target=\"_blank\" rel=\"noopener\" title=\"\">XSS (Cross-Site Scripting) attacks<\/a> is essential, but relatively simple if you follow rigorous guidelines.<\/p>\n\n\n\n<p>The fundamental principle to apply is: filter inputs and escape outputs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-1099399fd0330b06c2582eb2c18f88a5\" id=\"filter-inputs-and-escape-outputs\" style=\"color:#c0b800\">Filter inputs and escape outputs<\/h3>\n\n\n\n<p>All user data, whether it comes from forms, URLs (GET), POST requests, cookies or even HTTP headers, must be validated and filtered before being processed by your application. This includes hidden fields and all user input, whether visible or not.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Input filtering<\/strong>: Validate and sanitise all user data as soon as it is received. Use PHP filters such as <code>filter_var()<\/code> to ensure that the data matches your expectations (for example, an email, an integer or a URL).<\/li>\n\n\n\n<li><strong>Escaping output<\/strong>: Before displaying dynamic data on your site, escape it properly to prevent the injection of malicious scripts. Use PHP functions such as <code>htmlspecialchars()<\/code> to neutralise special characters such as \u2018&lt;\u2019, \u2018>\u2019, and \u2018&amp;\u2019. >\u2019 and \u201c&amp;\u201d.<\/li>\n<\/ul>\n\n\n\n<p>These simple measures can already prevent most standard XSS attacks.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-fe53ac3d1a35f60406ac11f44c3809a0\" id=\"strengthening-protection-with-http-headers\" style=\"color:#c0b800\">Strengthening protection with HTTP headers<\/h3>\n\n\n\n<p>Additional protection against XSS attacks can be implemented via HTTP headers. Headers such as <strong>Content-Security-Policy (CSP)<\/strong> can limit the execution of unapproved scripts or detect potential attacks.<\/p>\n\n\n\n<p>Content-Security-Policy lets you define which script sources are approved and authorised to run. By default, it prevents the execution of scripts injected via XSS.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-b3bbcbc5524c5a175c9ee0444ee62287\" id=\"cookies-protection\" style=\"color:#c0b800\">Cookies protection<\/h3>\n\n\n\n<p>Cookies should never be used to store sensitive information, as they are vulnerable to manipulation by the user or attacks such as XSS.<\/p>\n\n\n\n<p>Here are a few best practices for using cookies securely:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Don&#8217;t store sensitive information<\/strong>: Cookies are not inherently secure. Avoid using them for confidential or critical data.<\/li>\n\n\n\n<li><strong>Sign cookies<\/strong>: To protect cookies against manipulation, an effective method is to sign them by calculating a hash that you store in the cookie itself. When the cookie is sent back to the server, the latter can check its integrity by recalculating the hash.<\/li>\n\n\n\n<li><strong>Use security attributes<\/strong>: As indicated above for session hijacking, activate the HttpOnly and Secure attributes for your cookies.<\/li>\n<\/ul>\n\n\n\n<p>Example of attributes for a cookie:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>setcookie('user_session', $value, &#91;\n    'expires' => time() + 3600,\n    'path' => '\/',\n    'domain' => 'example.com',\n    'secure' => true,    \/\/ Cookie sent only via HTTPS\n    'httponly' => true,  \/\/ Inaccessible via JavaScript\n    'samesite' => 'Strict' \/\/ Prevents cookies being sent by cross-site requests\n]);<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"securing-file-uploads\">Securing File Uploads<\/h2>\n\n\n\n<p>File upload is a particularly sensitive feature. If poorly secured, it allows attackers to send malicious files to your server, including PHP scripts, which can lead to complete server takeovers. <\/p>\n\n\n\n<p>It is therefore essential to implement a robust security strategy.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-9a8cb17ee05f5399615585b4e06d1949\" id=\"restrict-access-to-authenticated-users\" style=\"color:#c0b800\">Restrict access to authenticated users<\/h3>\n\n\n\n<p>Only allow files to be uploaded by users who have been authenticated beforehand. This limits attack attempts from untrusted or anonymous users.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-57e409d623606c5b4a78ca54fd353f7c\" id=\"restrict-the-extensions-and-formats-accepted\" style=\"color:#c0b800\">Restrict the extensions and formats accepted<\/h3>\n\n\n\n<p>Only authorise file types that are strictly necessary for your functionalities (e.g. images, documents).<\/p>\n\n\n\n<p>Set up a white list of file extensions and accepted formats, such as .jpg, .png or .pdf. Reject all other formats.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-093eff3cd4dc14bdfbed310ca87865e1\" id=\"configure-an-htaccess-file-to-restrict-access-to-uploaded-files\" style=\"color:#c0b800\">Configure an .htaccess file to restrict access to uploaded files<\/h3>\n\n\n\n<p>In the directory where uploaded files are stored, place an .htaccess file to prevent malicious scripts from being executed.<\/p>\n\n\n\n<p>You can restrict access only to authorised file types:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>deny from all\n&lt;Files ~ \"\\.(gif|jpe?g|png|pdf)$\">\n    order deny,allow\n    allow from all\n&lt;\/Files><\/code><\/pre>\n\n\n\n<p>This configuration prevents the execution of PHP files or any other scripts that could be downloaded maliciously.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-0f6879d718d865e79ce292fb243d1c05\" id=\"validate-the-mime-type-and-file-extension\" style=\"color:#c0b800\">Validate the MIME type and file extension<\/h3>\n\n\n\n<p>Don&#8217;t rely solely on the file extension to validate its type. Use strict MIME type validation, checking that the file type corresponds to one of the authorised formats.<\/p>\n\n\n\n<p>For example, to validate an image, use functions such as <code>mime_content_type()<\/code> or <code>getimagesize()<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-6d28a0e3361b8c492f651dc2a0579501\" id=\"manage-files-securely-when-saving-them\" style=\"color:#c0b800\">Manage files securely when saving them<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Generate unique file names<\/strong>: Avoid using file names provided by users.<\/li>\n\n\n\n<li><strong>Store files outside the root directory<\/strong>: To prevent malicious files from being accidentally executed, store uploaded files outside your site&#8217;s root directory (for example, in a dedicated directory outside the public \u2018www\u2019 or \u2018htdocs\u2019 directory).<\/li>\n\n\n\n<li><strong>Revoke execution permissions<\/strong>: After saving the file, use <code>chmod()<\/code> to disable execution permissions, thus preventing any code from being executed.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-6009772f753e24ae6639dee373c3f312\" id=\"limit-file-size-with-upload_max_filesize\" style=\"color:#c0b800\">Limit file size with upload_max_filesize<\/h3>\n\n\n\n<p>You can configure the maximum file size globally via the php.ini file, by adjusting the upload_max_filesize parameter.<\/p>\n\n\n\n<p>If you want to set a stricter limit for a particular form, you can use the <code>MAX_FILE_SIZE<\/code> parameter in your HTML form. However, this limit must always be checked on the server side, as it can be modified by the user before the form is submitted.<\/p>\n\n\n\n<p>Example of a server-side check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if ($_FILES&#91;'file']&#91;'size'] > 1048576) { \/\/ 1MB\n    die(\"File too large.\");\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"protecting-against-csrf-cross-site-request-forgery-attacks\">Protecting Against CSRF (Cross Site Request Forgery) Attacks<\/h2>\n\n\n\n<p><a href=\"https:\/\/www.vaadata.com\/blog\/csrf-attacks-principles-impacts-exploitations-security-best-practices\/\" target=\"_blank\" rel=\"noopener\" title=\"\">CSRF attacks<\/a> exploit the trust that a site places in an authenticated user, forcing the latter to perform unwanted actions. To protect yourself.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-826847fe1a29359da029744d4d7b1399\" id=\"use-post-requests-for-sensitive-actions\" style=\"color:#c0b800\">Use POST requests for sensitive actions<\/h3>\n\n\n\n<p>The first step in reducing the risk of CSRF attacks is to ensure that all actions involving state changes (such as creating, modifying or deleting data) are performed via POST requests, and not GET requests.<\/p>\n\n\n\n<p>While this does not completely eliminate the risk of CSRF attacks, it does reduce the basic attacks where an attacker could exploit a GET request (such as a simple click on a malicious link) to trigger an action.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-5b9dcc7a443e08029df8a3bb8d1b6d52\" id=\"implement-csrf-tokens-in-forms\" style=\"color:#c0b800\">Implement CSRF tokens in forms<\/h3>\n\n\n\n<p>The most effective method of protecting against CSRF attacks is to use CSRF tokens.<\/p>\n\n\n\n<p>These tokens are unique values generated by the server and associated with the user&#8217;s session. When a form is submitted, the server compares the token sent with the token stored in the user&#8217;s session to validate the authenticity of the request. If the tokens do not match, the action is rejected.<\/p>\n\n\n\n<p>Here&#8217;s how to implement a simple CSRF token.<\/p>\n\n\n\n<p><strong>Generate a token when a form is created:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$_SESSION&#91;'csrf_token'] = bin2hex(random_bytes(32));<\/code><\/pre>\n\n\n\n<p><strong>Add the token to the form as a hidden field:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;form method=\"POST\" action=\"\/submit\">\n    &lt;input type=\"hidden\" name=\"csrf_token\" value=\"&lt;?php echo $_SESSION&#91;'csrf_token']; ?>\">\n    &lt;!-- other fields -->\n    &lt;button type=\"submit\">Submit&lt;\/button>\n&lt;\/form><\/code><\/pre>\n\n\n\n<p><strong>Check the token on the server side when it is submitted:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if ($_POST&#91;'csrf_token'] !== $_SESSION&#91;'csrf_token']) {\n    die(\"Invalid CSRF token\");\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading has-text-color has-link-color wp-elements-a45b1983e252e657b4dab41862414d8c\" id=\"use-anti-csrf-libraries-or-frameworks\" style=\"color:#c0b800\">Use anti-CSRF libraries or frameworks<\/h3>\n\n\n\n<p>If you&#8217;re working with a framework, many modern solutions already include built-in CSRF protection.<\/p>\n\n\n\n<p>For example, Laravel, Symfony and Django automatically generate and check CSRF tokens in forms.<\/p>\n\n\n\n<p>If you&#8217;re not working with a framework that offers this protection natively, you can either implement the tokens yourself or use third-party libraries.<\/p>\n\n\n\n<h2 class=\"wp-block-heading has-black-color has-text-color has-link-color wp-elements-4bf96d38753bf214827922ec3e9a9c58\" id=\"conclusion\">Conclusion<\/h2>\n\n\n\n<p>Adopting robust security practices is essential for protecting PHP applications against threats and vulnerabilities.<\/p>\n\n\n\n<p>The various common attacks can be anticipated and reduced by systematically implementing best security practices. However, these security measures can be complex and time-consuming to implement manually in each project.<\/p>\n\n\n\n<p>This is where modern frameworks provide an advantageous solution for developers. Integrating a framework offers a number of advantages:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Built-in security features<\/strong>: Modern frameworks often offer built-in protection against common vulnerabilities. For example, the use of prepared statements to counter SQL injections, automatic input filtering to prevent XSS attacks, or the management of anti-CSRF tokens.<\/li>\n\n\n\n<li><strong>Simplified maintenance<\/strong>: The frameworks benefit from an active community of developers who provide regular updates, correcting identified vulnerabilities and ensuring continuous improvement of security standards. This considerably reduces the risk of exploits from obsolete components.<\/li>\n\n\n\n<li><strong>Saving time and reducing costs<\/strong>: By automating many aspects of security and offering ready-to-use libraries, frameworks enable teams to concentrate on business-specific issues, without having to develop security solutions from scratch. This time saving also translates into optimised development resources and costs.<\/li>\n\n\n\n<li><strong>Consolidated best practice<\/strong>: The frameworks are designed around proven and tested principles. They incorporate solid architectures that promote modular and secure development, limiting human error and facilitating long-term code maintenance.<\/li>\n<\/ul>\n\n\n\n<p><strong>Author: Amin TRAOR\u00c9 &#8211; CMO @Vaadata<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"class_list":{"0":"post-11179","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-technical"},"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/posts\/11179","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/comments?post=11179"}],"version-history":[{"count":13,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/posts\/11179\/revisions"}],"predecessor-version":[{"id":11194,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/posts\/11179\/revisions\/11194"}],"wp:attachment":[{"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/media?parent=11179"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/categories?post=11179"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/tags?post=11179"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}