Lesson 9 / 31
Input Validation and Output Encoding
Validate input with allow-lists and encode output for its context to prevent cross-site scripting.
By Rahul Agarwal · 15 years in web development
Validate in, encode out
Two complementary habits stop a large share of web bugs. Input validation checks that incoming data has the expected type, length, format and range, preferably with an allow-list (what is permitted) rather than a deny-list (what is forbidden), because attackers are creative at finding forms you did not think to deny. Validate on the server; client-side checks are only a convenience. Output encoding transforms data when you place it into a specific context so it cannot break out: HTML-encode text placed into a page, use URL encoding in query strings, JSON-encode for scripts. Cross-site scripting (XSS) happens when user text reaches an HTML page without encoding and the browser runs it as script. Modern template engines such as Jinja2, React's JSX and Angular's templates encode by default; bugs appear when developers bypass that with raw-HTML features. A Content-Security-Policy header adds a second layer by restricting which scripts may run.
Encoding for the HTML context
Python's standard library encodes the five HTML-special characters.
import html, re
comment = '<script>alert("hi")</script>'
print(html.escape(comment))
PINCODE = re.compile(r"[1-9][0-9]{5}") # allow-list: Indian PIN format
for value in ["560001", "56A001", "0123456"]:
print(value, bool(PINCODE.fullmatch(value)))
Output:
<script>alert("hi")</script> 560001 True 56A001 False 0123456 False
Raw-HTML escape hatches
Search your code for innerHTML, React's dangerouslySetInnerHTML, Angular's bypassSecurityTrust* and Jinja's |safe. Each one turns off automatic encoding and deserves a review comment.
Quick check: Which approach to input validation is generally stronger?
- A deny-list of known bad strings
- Client-side JavaScript checks only
- No validation, relying only on a firewall
- An allow-list describing exactly what valid input looks like
Answer
An allow-list describing exactly what valid input looks like — Allow-lists fail safe: anything not explicitly valid is rejected, so unknown attack forms are blocked too.