Classic character and filter bypass patterns in cross-site scripting
跨站脚本测试与过滤绕过技术概览
In the early 2010s, many web applications tried to stop cross-site scripting (XSS) by blocking a handful of individual characters, most often angle brackets or quotes, rather than properly encoding output for the context it appeared in. This note looks at why that approach kept failing, as a case study in output-encoding discipline rather than a how-to.
Why single-character filters failed
Blocking one character, such as a quote mark, rarely removes the underlying problem if the surrounding markup still lets an attacker influence an HTML attribute or a script context. Testers of that era found that encoding tricks, alternative event handlers, or simply moving the injection point to a different part of the markup let a blocked character's effect be reproduced without ever submitting it directly. The lesson was that filtering has to account for every place tainted data can land, not just the characters an attacker might type.
Browser-level XSS filters were a stopgap, not a fix
Around the same period, Internet Explorer and some other browsers shipped heuristic XSS filters that tried to spot reflected attack patterns in a request and neutralise them in the response. These filters only ever addressed reflected XSS, a single class among several (reflected, stored and DOM-based), and their pattern matching could be evaded by altering whitespace, encoding, or the structure of a payload just enough to fall outside the heuristic while still executing in the browser.
What this means for defenders today
Modern practice has mostly moved past relying on either technique. Context-aware output encoding, a strict Content Security Policy, and treating all user input as untrusted at the point it is rendered close off entire classes of bypass rather than chasing individual characters. Browser-level reflected-XSS filters have also been retired by major browsers in favour of CSP, since a heuristic filter in the browser can never know the application's intended context as well as the application itself does.
Takeaway for builders
If a security control can be described as "block this character", it is worth asking what happens when the same effect is achieved without that character. Durable defences fix the output context, not the input characters.
Key takeaways
- Blocking individual characters rarely stops XSS if the output context is still unsafe.
- Browser-level heuristic XSS filters only ever covered reflected XSS, one of several XSS classes.
- Context-aware output encoding and CSP address the underlying problem rather than specific payloads.
- A security control built around named characters should be tested against equivalent payloads that avoid them.
中文摘要
本文回顾了早期跨站脚本测试中常见的字符过滤与浏览器内置XSS过滤器绕过思路,并说明为何这类防护手段最终被上下文相关的输出编码和CSP所取代。
This note has been rewritten and checked for this edition; it is not a copy of the original post.