hibernate-validator 6.0.18中@SafeHtml已废弃,自定义XSS验证是否正确?
Hey there! Let's break down your question about replacing the deprecated @SafeHtml annotation with a custom XSS validator.
Is Your Current Implementation Correct?
Your validator checks if the input string matches its HTML-escaped version using Spring's HtmlUtils.htmlEscape(). This logic works for basic HTML injection cases—it will catch unescaped special characters like <, >, &, and " that could be used to inject raw HTML into pages.
But it has a critical limitation: it only covers a small subset of XSS attack vectors. For example, malicious strings like javascript:alert('xss') or vbscript:evil() don't contain HTML special characters, so HtmlUtils.htmlEscape() leaves them unchanged. Your validator would incorrectly mark these as "safe," even though they pose a serious XSS risk if rendered in contexts like link URLs or script blocks.
So in short: your implementation is correct for basic HTML character injection, but it's not robust enough to cover all common XSS threats.
Better Implementation Options
To build a more secure validator, leverage dedicated security libraries that handle a wider range of attack scenarios. Here are two reliable approaches:
1. Use OWASP Java Encoder
OWASP's encoder library is purpose-built for XSS protection, with context-specific encoding for HTML, JavaScript, CSS, and more. It handles edge cases that basic HTML escaping misses.
Example implementation:
import org.owasp.encoder.Encode; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class XssValidator implements ConstraintValidator<XssEscape, String> { @Override public boolean isValid(String input, ConstraintValidatorContext context) { if (input == null) { return true; // Adjust this if null should be considered invalid } // Validate input for HTML context (use Encode.forJavaScript() for script contexts) return Encode.forHtml(input).equals(input); } }
2. Use Jsoup for HTML Sanitization
If you need to allow some safe HTML tags (like <b>, <i>) but block dangerous ones (like <script>, <iframe>), Jsoup's whitelist-based sanitization is ideal. It strips out any unapproved tags/attributes automatically.
Example implementation:
import org.jsoup.Jsoup; import org.jsoup.safety.Whitelist; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class XssValidator implements ConstraintValidator<XssEscape, String> { // Use a strict whitelist—customize to allow safe tags if needed private static final Whitelist SAFE_WHITELIST = Whitelist.none(); @Override public boolean isValid(String input, ConstraintValidatorContext context) { if (input == null) { return true; } // Check if sanitized input matches original (no dangerous content was removed) return Jsoup.clean(input, SAFE_WHITELIST).equals(input); } }
Bonus: Combine Validation with Automatic Escaping
For extra safety, consider automatically escaping input at the entry point (like DTO setters or controller layers) instead of just validating. This ensures data is safe even if validation slips through:
public class UserProfileDto { private String bio; public void setBio(String bio) { this.bio = Encode.forHtml(bio); // Auto-escape on input } }
Final Tips
- Explicitly document how your validator handles
nullvalues (your current code treatsnullas valid, which is usually acceptable but worth noting). - Pair backend protection with a Content Security Policy (CSP) on the frontend. CSP blocks unauthorized scripts from running, adding a second layer of defense against XSS.
内容的提问来源于stack exchange,提问作者Nikolay Larin

