XssSanitizerImpl.java

package org.example.websecurity;

/*
 * This is free and unencumbered software released into the public domain.
 * Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, 
 * either in source code form or as a compiled binary, for any purpose, commercial or 
 * non-commercial, and by any means.
 * 
 * In jurisdictions that recognize copyright laws, the author or authors of this 
 * software dedicate any and all copyright interest in the software to the public domain. 
 * We make this dedication for the benefit of the public at large and to the detriment of 
 * our heirs and successors. We intend this dedication to be an overt act of relinquishment in 
 * perpetuity of all present and future rights to this software under copyright law.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES 
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 * For more information, please refer to: https://unlicense.org/
*/

import org.apache.commons.text.StringEscapeUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;

/**
 * This is the utility class to sanitize String against XSS attacks.
 * <br>
 * 
 * @author Jonathan Earl
 * @version 1.0
 *
 */
public class XssSanitizerImpl
	implements XssSanitizer
{
	private static final Logger LOG = LogManager.getLogger(XssSanitizerImpl.class);
	
	private Safelist rules = null;
	
	/**
	 * This default constructor.
	 * <p>
	 * This will load the "none" rules.
	 * 
	 */
	public XssSanitizerImpl()
	{
		LOG.debug("Starting constructor");
		Safelist defaultRules = Safelist.none();
		LOG.trace("Setting default rules to Safelist.none");
		setRules(defaultRules);
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Safelist getRules()
	{
		LOG.debug("Returnung the current rules: " + rules.toString());
		return rules;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setRules(final Safelist rulesIn)
	{
		LOG.debug("Setting the rules");
		if (rulesIn == null)
		{
			LOG.error("Attempt to set the rules to null");
			throw new IllegalArgumentException("The rules must be provided");
		}
		LOG.trace("New rules are: " + rulesIn.toString());
		this.rules = rulesIn;
	}	

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String sanitizeInput(final String input)
	{
		LOG.debug("Sanitizing inout");
		if (input == null)
		{
			LOG.error("Attempt to sanitize null string");
			throw new IllegalArgumentException("Input required");
		}
		
		LOG.trace("Pre sanitized string: " + sanitizeOutput(input));
		String results = Jsoup.clean(input, rules);
		LOG.trace("Post sanitized string: " + results);
		return results.trim();
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public String sanitizeOutput(final String input)
	{
		LOG.debug("Sanitizing output");
		if (input == null)
		{
			LOG.error("Attempt to sanitize null string");
			throw new IllegalArgumentException("Input required");
		}
		
		String temp = input.trim();
		return StringEscapeUtils.escapeHtml4(temp);
	}
}