Preventing XSS in Spring Boot — Especially for @RequestBody String
⚠️ The Problem
Many developers assume XSS (Cross-Site Scripting) is purely a frontend concern.
But if you’re accepting raw String
inputs in a Spring Boot controller — especially using @RequestBody
— and rendering them back in a web page or API without sanitization, you're opening the door to XSS vulnerabilities.
🚨 Dangerous Code Example
@PostMapping("/submit")
public ResponseEntity<String> submit(@RequestBody String comment) {
// Later returned in UI or logs
return ResponseEntity.ok(comment);
}
A malicious user can send:
"<script>alert('XSS')</script>"
If you render that back in an HTML page or inject into logs, your users could be exposed.
🧼 The Solution: Sanitize Inputs
To protect against XSS in this case, you should sanitize any input that could later be rendered as HTML or interpreted by a browser.
✅ Use OWASP Java HTML Sanitizer
A robust and customizable library maintained by OWASP:
Gradle:
implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20211018.1'
Maven:
<dependency>
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
<artifactId>owasp-java-html-sanitizer</artifactId>
<version>20211018.1</version>
</dependency>
✅ Example with Sanitization
import org.owasp.html.PolicyFactory;
import org.owasp.html.Sanitizers;
@RestController
public class CommentController { private final PolicyFactory policy = Sanitizers.FORMATTING.and(Sanitizers.LINKS); @PostMapping("/submit")
public ResponseEntity<String> submit(@RequestBody String comment) {
String sanitized = policy.sanitize(comment);
return ResponseEntity.ok(sanitized);
}
}
This allows some formatting and links, but strips out dangerous tags like <script>
, <img onerror>
, etc.
🔧 Alternative: Custom XSS Filter for JSON Fields
If you’re using DTOs instead of raw strings, you can:
- Add a Jackson deserializer
- Or apply sanitization in your service/controller layer.
Example:
@PostMapping("/submit")
public ResponseEntity<Comment> submit(@RequestBody Comment comment) {
comment.setText(policy.sanitize(comment.getText()));
return ResponseEntity.ok(comment);
}
❗ Do Not Do This:
String sanitized = comment.replaceAll("<", "<")
.replaceAll(">", ">");
This is not reliable, and attackers can bypass such naive filters easily.
🧠 Best Practices
- Sanitize inputs as early as possible
- Log only sanitized or encoded data
- Avoid rendering raw user input into web pages
- Consider frontend escaping (
[[${comment}]]
in Thymeleaf, etc.) - Use Content Security Policy (CSP) headers where applicable
🛡️ Summary
XSS vulnerabilities can creep in anywhere untrusted user input is handled.
Even server-side endpoints like @RequestBody String
can become a threat vector if their outputs are not properly sanitized.
Sanitize on input, validate on process, and escape on output.
💬 Have you audited your Spring Boot endpoints lately?
Let’s make XSS a thing of the past.
#Java #SpringBoot #WebSecurity #OWASP #XSS #BackendSecurity #SecureCoding