Cross-Site Scripting (XSS) is one of the most common security vulnerabilities that web developers face. It occurs when an attacker is able to inject malicious scripts into web pages viewed by other users. This can lead to a range of issues, including stealing user data, session hijacking, and executing arbitrary actions on behalf of the user.
In this article, I will dive into different contexts where XSS vulnerabilities can occur, and more importantly, how we can defend against them using PHP. From injecting scripts into HTML tag content to manipulating JavaScript event handlers and URL parameters, XSS attacks can take many forms. We’ll look at how untrusted data (such as user input) can be manipulated in each of these contexts, and how encoding and sanitization can help mitigate these risks.
What You Will Learn:
- Common XSS attack vectors and how attackers exploit them.
- How to defend against XSS in different contexts, such as HTML, JavaScript, and URLs.
- PHP best practices for preventing XSS using built-in functions like
htmlspecialchars()
,urlencode()
, and custom encoding strategies. - Real-world code examples of XSS attacks and defenses in PHP.
Injection into Tag Content | |
Code Fragment |
|
Attack Method | Common attack where an HTML tag is added, e.g.:
|
Defense Method | Convert special characters into HTML entities, like:
|
Injection into Attribute Content | |
Code Fragment |
|
Attack Method | Escape the class attribute or create a new HTML attribute with JS. Examples:
|
Defense Method | Convert special characters into HTML entities, like:
|
Injection into HREF Attribute | |
Code Fragment |
|
Attack Method | Escape the href attribute using the javascript: protocol:
The javascript: protocol allows the attacker to execute JavaScript code by crafting a malicious URL. This URL triggers JavaScript execution upon clicking the link. |
Defense Method | Validate the protocol and accept only HTTP/HTTPS URLs.
|
Injection into String Inside JS Code | |
Code Fragment |
|
Attack Method | The XSS attack happens when an attacker inserts JavaScript code inside a JavaScript string:
Many applications try to protect themselves against this attack by preventing escaping from the string and encoding the quote " as \\. Assuming this is the only replacement, it is still insufficient. If we add our own character, for example \\, this will replace \" with \\, making the quote no longer able to close the string.
Even if this is done correctly, there is still a very common method in use, which, despite everything, allows executing custom JS code:
The first script tag contains a naturally occurring syntax error (an unclosed string). However, from the attacker's perspective, this is irrelevant, as the next script tag will execute normally, enabling the use of XSS.
|
Defense Method | In case PHP and 2 above mentioned samples, htmlspecialchars will protect, as it escapes quotes and script tags, but it is recommenede to use additionally UTF-16 encoding for non-alphanumeric characters, e.g., \uXXXX to be sure at 100% xss injection would not happen, like:
|
Injection in the onclick Attribute | |
Code Fragment |
|
Attack Method | We assume that change() function exists at JS context. At first glance, it seems that standard protection for HTML attributes, such as escaping special characters, can prevent this attack. However, let’s see what happens if the attacker enters the following code:
Looking at raw HTML code, initially, it may be hard to spot why XSS will succeed here. The apostrophe is replaced by ' - but in this case, this is not sufficient because the browser automatically decodes all HTML entities found in attribute values. Therefore, the JS engine will see the code as:
This example shows that protecting against XSS cannot be approached lightly. It is worth to keep in mind that some attributes have special meaning. For example, the content of the onclick attribute is treated as JS code, meaning the attacker does not need to escape this attribute.
|
Defense Method | Encode both HTML attributes and JavaScript strings. Look at function filter($input) {...} sample above. |
Injection in the href Attribute within the JS Protocol | |
Code Fragment |
|
Attack Method | Here, the attacker is exploiting multiple contexts: the HTML attribute, JavaScript, and URL encoding. The injected payload is URL-encoded, allowing the malicious code to bypass basic filters. For example:
In this case, the `%27` (which represents an apostrophe) is decoded by the browser, allowing the JS engine to execute the attack as at example above |
Defense Method | Apply three-layer encoding:
|
Thank you for your attentions. If you are interested in similar content, then sign up to my newsletter: