All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.owasp.esapi.codecs.JavaScriptCodec Maven / Gradle / Ivy

Go to download

The Enterprise Security API (ESAPI) project is an OWASP project to create simple strong security controls for every web platform. Security controls are not simple to build. You can read about the hundreds of pitfalls for unwary developers on the OWASP website. By providing developers with a set of strong controls, we aim to eliminate some of the complexity of creating secure web applications. This can result in significant cost savings across the SDLC.

There is a newer version: 2.5.5.0
Show newest version
/**
 * OWASP Enterprise Security API (ESAPI)
 * 
 * This file is part of the Open Web Application Security Project (OWASP)
 * Enterprise Security API (ESAPI) project. For details, please see
 * http://www.owasp.org/index.php/ESAPI.
 *
 * Copyright (c) 2007 - The OWASP Foundation
 * 
 * The ESAPI is published by OWASP under the BSD license. You should read and accept the
 * LICENSE before you use, modify, and/or redistribute this software.
 * 
 * @author Jeff Williams Aspect Security
 * @created 2007
 */
package org.owasp.esapi.codecs;


/**
 * Implementation of the Codec interface for backslash encoding in JavaScript.
 * 
 * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) Aspect Security
 * @since June 1, 2007
 * @see org.owasp.esapi.Encoder
 */
public class JavaScriptCodec extends Codec {


	/**
	 * {@inheritDoc}
	 * 
	 * Returns backslash encoded numeric format. Does not use backslash character escapes
	 * such as, \" or \' as these may cause parsing problems. For example, if a javascript
	 * attribute, such as onmouseover, contains a \" that will close the entire attribute and
	 * allow an attacker to inject another script attribute.
     *
     * @param immune
     */
	public String encodeCharacter( char[] immune, Character c ) {

		// check for immune characters
		if ( containsCharacter(c, immune ) ) {
			return ""+c;
		}
		
		// check for alphanumeric characters
		String hex = Codec.getHexForNonAlphanumeric(c);
		if ( hex == null ) {
			return ""+c;
		}
				
		// Do not use these shortcuts as they can be used to break out of a context
		// if ( ch == 0x00 ) return "\\0";
		// if ( ch == 0x08 ) return "\\b";
		// if ( ch == 0x09 ) return "\\t";
		// if ( ch == 0x0a ) return "\\n";
		// if ( ch == 0x0b ) return "\\v";
		// if ( ch == 0x0c ) return "\\f";
		// if ( ch == 0x0d ) return "\\r";
		// if ( ch == 0x22 ) return "\\\"";
		// if ( ch == 0x27 ) return "\\'";
		// if ( ch == 0x5c ) return "\\\\";

		// encode up to 256 with \\xHH
        String temp = Integer.toHexString(c);
		if ( c < 256 ) {
	        String pad = "00".substring(temp.length() );
	        return "\\x" + pad + temp.toUpperCase();
		}

		// otherwise encode with \\uHHHH
        String pad = "0000".substring(temp.length() );
        return "\\u" + pad + temp.toUpperCase();
	}

	
	/**
	 * {@inheritDoc}
	 * 
	 * Returns the decoded version of the character starting at index, or
	 * null if no decoding is possible.
	 * See http://www.planetpdf.com/codecuts/pdfs/tutorial/jsspec.pdf 
	 * Formats all are legal both upper/lower case:
	 *   \\a - special characters
	 *   \\xHH
	 *   \\uHHHH
	 *   \\OOO (1, 2, or 3 digits)
	 */
	public Character decodeCharacter( PushbackString input ) {
		input.mark();
		Character first = input.next();
		if ( first == null ) {
			input.reset();
			return null;
		}
		
		// if this is not an encoded character, return null
		if (first != '\\' ) {
			input.reset();
			return null;
		}

		Character second = input.next();
		if ( second == null ) {
			input.reset();
			return null;
		}
		
		// \0 collides with the octal decoder and is non-standard
		// if ( second.charValue() == '0' ) {
		//	return Character.valueOf( (char)0x00 );
		if (second == 'b' ) {
			return 0x08;
		} else if (second == 't' ) {
			return 0x09;
		} else if (second == 'n' ) {
			return 0x0a;
		} else if (second == 'v' ) {
			return 0x0b;
		} else if (second == 'f' ) {
			return 0x0c;
		} else if (second == 'r' ) {
			return 0x0d;
		} else if (second == '\"' ) {
			return 0x22;
		} else if (second == '\'' ) {
			return 0x27;
		} else if (second == '\\' ) {
			return 0x5c;
			
		// look for \\xXX format
		} else if ( Character.toLowerCase( second.charValue() ) == 'x' ) {
			// Search for exactly 2 hex digits following
			StringBuilder sb = new StringBuilder();
			for ( int i=0; i<2; i++ ) {
				Character c = input.nextHex();
				if ( c != null ) sb.append( c );
				else {
					input.reset();
					return null;
				}
			}
			try {
				// parse the hex digit and create a character
				int i = Integer.parseInt(sb.toString(), 16);
                if (Character.isValidCodePoint(i)) {
                    return (char) i;
                }
			} catch( NumberFormatException e ) {
				// throw an exception for malformed entity?
				input.reset();
				return null;
			}
			
		// look for \\uXXXX format
		} else if ( Character.toLowerCase( second.charValue() ) == 'u') {
			// Search for exactly 4 hex digits following
			StringBuilder sb = new StringBuilder();
			for ( int i=0; i<4; i++ ) {
				Character c = input.nextHex();
				if ( c != null ) sb.append( c );
				else {
					input.reset();
					return null;
				}
			}
			try {
				// parse the hex string and create a character
				int i = Integer.parseInt(sb.toString(), 16);
                if (Character.isValidCodePoint(i)) {
                    return (char) i;
                }
			} catch( NumberFormatException e ) {
				// throw an exception for malformed entity?
				input.reset();
				return null;
			}
			
		// look for one, two, or three octal digits
		} else if ( PushbackString.isOctalDigit(second) ) {
			StringBuilder sb = new StringBuilder();
            // get digit 1
            sb.append(second);
            
            // get digit 2 if present
            Character c2 = input.next();
            if ( !PushbackString.isOctalDigit(c2) ) {
            	input.pushback( c2 );
            } else {
            	sb.append( c2 );
	            // get digit 3 if present
	            Character c3 = input.next();
	            if ( !PushbackString.isOctalDigit(c3) ) {
	            	input.pushback( c3 );
	            } else {
	            	sb.append( c3 );
	            }
            }
			try {
				// parse the octal string and create a character
				int i = Integer.parseInt(sb.toString(), 8);
                if (Character.isValidCodePoint(i)) {
                    return (char) i;
                }
			} catch( NumberFormatException e ) {
				// throw an exception for malformed entity?
				input.reset();
				return null;
			}
		}
		
		// ignore the backslash and return the character
		return second;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy