/* * Copyright (c) 2002-2014, Mairie de Paris * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice * and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice * and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * License 1.0 */ package fr.paris.lutece.util.http; import fr.paris.lutece.util.string.StringUtil; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import java.util.Enumeration; import javax.servlet.http.HttpServletRequest; /** * Security utils * */ public final class SecurityUtil { private static final String LOGGER_NAME = "lutece.security.http"; private static final String CONSTANT_HTTP_HEADER_X_FORWARDED_FOR = "X-Forwarded-For"; private static final String PATTERN_IP_ADDRESS = "^([0-9]{1,3}\\.){3}[0-9]{1,3}$"; private static final String CONSTANT_COMMA = ","; // private static final String PATTERN_CLEAN_PARAMETER = "^[\\w/]+$+"; /** * Private Constructor */ private SecurityUtil( ) { } /** * Scan request parameters to see if there no malicious code. * * @param request * The HTTP request * @return true if all parameters don't contains any special characters */ public static boolean containsCleanParameters( HttpServletRequest request ) { return containsCleanParameters( request, null ); } /** * Scan request parameters to see if there no malicious code. * * @param request * The HTTP request * @param strXssCharacters * a String wich contain a list of Xss characters to check in strValue * @return true if all parameters don't contains any special characters */ public static boolean containsCleanParameters( HttpServletRequest request, String strXssCharacters ) { String key; String [ ] values; Enumeration<String> e = request.getParameterNames( ); while ( e.hasMoreElements( ) ) { key = e.nextElement( ); values = request.getParameterValues( key ); int length = values.length; for ( int i = 0; i < length; i++ ) { if ( SecurityUtil.containsXssCharacters( request, values [i], strXssCharacters ) ) { Logger logger = Logger.getLogger( LOGGER_NAME ); logger.warn( "SECURITY WARNING : INVALID REQUEST PARAMETERS" + dumpRequest( request ) ); return false; } } } return true; } /** * Checks if a String contains characters that could be used for a cross-site scripting attack. * * @param request * The HTTP request * @param strString * a character String * @return true if the String contains illegal characters */ public static boolean containsXssCharacters( HttpServletRequest request, String strString ) { return containsXssCharacters( request, strString, null ); } /** * Checks if a String contains characters that could be used for a cross-site scripting attack. * * @param request * The HTTP request * @param strValue * a character String * @param strXssCharacters * a String wich contain a list of Xss characters to check in strValue * @return true if the String contains illegal characters */ public static boolean containsXssCharacters( HttpServletRequest request, String strValue, String strXssCharacters ) { boolean bContains = ( strXssCharacters == null ) ? StringUtil.containsXssCharacters( strValue ) : StringUtil.containsXssCharacters( strValue, strXssCharacters ); if ( bContains ) { Logger logger = Logger.getLogger( LOGGER_NAME ); logger.warn( "SECURITY WARNING : XSS CHARACTERS DETECTED" + dumpRequest( request ) ); } return bContains; } /** * Dump all request info * * @param request * The HTTP request * @return A report containing all request info */ public static String dumpRequest( HttpServletRequest request ) { StringBuffer sbDump = new StringBuffer( "\r\n Request Dump : \r\n" ); dumpTitle( sbDump, "Request variables" ); dumpVariables( sbDump, request ); dumpTitle( sbDump, "Request parameters" ); dumpParameters( sbDump, request ); dumpTitle( sbDump, "Request headers" ); dumpHeaders( sbDump, request ); return sbDump.toString( ); } /** * Get the IP of the user from a request. If the user is behind an apache server, return the ip of the user instead of the ip of the server. * * @param request * The request * @return The IP of the user that made the request */ public static String getRealIp( HttpServletRequest request ) { String strIPAddress = request.getHeader( CONSTANT_HTTP_HEADER_X_FORWARDED_FOR ); if ( strIPAddress != null ) { String strIpForwarded = null; while ( !strIPAddress.matches( PATTERN_IP_ADDRESS ) && strIPAddress.contains( CONSTANT_COMMA ) ) { strIpForwarded = strIPAddress.substring( 0, strIPAddress.indexOf( CONSTANT_COMMA ) ); strIPAddress = strIPAddress.substring( strIPAddress.indexOf( CONSTANT_COMMA ) ).replaceFirst( CONSTANT_COMMA, StringUtils.EMPTY ).trim( ); if ( ( strIpForwarded != null ) && strIpForwarded.matches( PATTERN_IP_ADDRESS ) ) { strIPAddress = strIpForwarded; } } if ( !strIPAddress.matches( PATTERN_IP_ADDRESS ) ) { strIPAddress = request.getRemoteAddr( ); } } else { strIPAddress = request.getRemoteAddr( ); } return strIPAddress; } /** * Write a title into the dump stringbuffer * * @param sbDump * The dump stringbuffer * @param strTitle * The title */ private static void dumpTitle( StringBuffer sbDump, String strTitle ) { sbDump.append( "** " ); sbDump.append( strTitle ); sbDump.append( " **\r\n" ); } /** * Write request variables into the dump stringbuffer * * @param sb * The dump stringbuffer * @param request * The HTTP request */ private static void dumpVariables( StringBuffer sb, HttpServletRequest request ) { dumpVariable( sb, "AUTH_TYPE", request.getAuthType( ) ); dumpVariable( sb, "REQUEST_METHOD", request.getMethod( ) ); dumpVariable( sb, "PATH_INFO", request.getPathInfo( ) ); dumpVariable( sb, "PATH_TRANSLATED", request.getPathTranslated( ) ); dumpVariable( sb, "QUERY_STRING", request.getQueryString( ) ); dumpVariable( sb, "REQUEST_URI", request.getRequestURI( ) ); dumpVariable( sb, "SCRIPT_NAME", request.getServletPath( ) ); dumpVariable( sb, "LOCAL_ADDR", request.getLocalAddr( ) ); dumpVariable( sb, "SERVER_PROTOCOL", request.getProtocol( ) ); dumpVariable( sb, "REMOTE_ADDR", request.getRemoteAddr( ) ); dumpVariable( sb, "REMOTE_HOST", request.getRemoteHost( ) ); dumpVariable( sb, "HTTPS", request.getScheme( ) ); dumpVariable( sb, "SERVER_NAME", request.getServerName( ) ); dumpVariable( sb, "SERVER_PORT", String.valueOf( request.getServerPort( ) ) ); } /** * Write request headers infos into the dump stringbuffer * * @param sb * The dump stringbuffer * @param request * The HTTP request */ private static void dumpHeaders( StringBuffer sb, HttpServletRequest request ) { Enumeration<String> values; String key; Enumeration<String> headers = request.getHeaderNames( ); while ( headers.hasMoreElements( ) ) { key = headers.nextElement( ); values = request.getHeaders( key ); while ( values.hasMoreElements( ) ) { dumpVariable( sb, key, values.nextElement( ) ); } } } /** * Write request parameters infos into the dump stringbuffer * * @param sb * The dump stringbuffer * @param request * The HTTP request */ private static void dumpParameters( StringBuffer sb, HttpServletRequest request ) { String key; String [ ] values; Enumeration<String> e = request.getParameterNames( ); while ( e.hasMoreElements( ) ) { key = e.nextElement( ); values = request.getParameterValues( key ); int length = values.length; for ( int i = 0; i < length; i++ ) { dumpVariable( sb, key, values [i] ); } } } /** * Write name / value infos into the dump stringbuffer * * @param sb * The dump string buffer * @param strName * The info name * @param strValue * The info value */ private static void dumpVariable( StringBuffer sb, String strName, String strValue ) { sb.append( strName ); sb.append( " : \"" ); sb.append( strValue ); sb.append( "\"\r\n" ); } }