diff --git a/configuration/esapi/ESAPI.properties b/configuration/esapi/ESAPI.properties index b5b6aacc6..2b24814d9 100644 --- a/configuration/esapi/ESAPI.properties +++ b/configuration/esapi/ESAPI.properties @@ -556,3 +556,30 @@ Validator.HtmlValidationAction=throw # This is the default behaviour of ESAPI. # #Validator.HtmlValidationConfigurationFile=antisamy-esapi.xml + +######################################################################################## +# The following methods are now disabled in the default configuration and must +# be explicity enabled. If you try to invoke a method disabled by default, ESAPI +# will thrown a NotConfiguredByDefaultException. +# +# The reason for this varies, but ranges from they are not really suitable for +# enterprise scale to that are only marginally tested (if at all) versus the are +# unsafe for general use, although them may be fine when combined with other +# security-in-depth techiques. +# +# The disabled-by-default methods are: +# org.owasp.esapi.reference.DefaultEncoder.encodeForSQL +# org.owasp.esapi.ESAPI.accessController [FUTURE; will correspond to deprecation notice] +# +# Mote details to explain this may be found in the ESAPI GitHub wiki article at +# https://github.com/ESAPI/esapi-java-legacy/wiki/Reducing-the-ESAPI-Library's-Attack-Surface +########### +# The format is a comma-separated list of fully.Qualified.ClassName.methodName; +# all class names must begin with "org.owasp.esapi.". +ESAPI.dangerouslyAllowUnsafeMethods.methodNames= +########### +# Normally you would put some text here (that will be logged) that provides some +# justification as to why you have enabled these functions. This can be +# anythuing such as a Jira or ServiceNow ticket number, a security exception +# reference, etc. If it is left empty, it will just like "Justification: none".` +ESAPI.enableLegCannonModeAndGetMyAssFired.justification= diff --git a/pom.xml b/pom.xml index 8c954c6bd..e69d57aa4 100644 --- a/pom.xml +++ b/pom.xml @@ -643,7 +643,7 @@ 3.11.2 8 - none + none diff --git a/src/main/java/org/owasp/esapi/Encoder.java b/src/main/java/org/owasp/esapi/Encoder.java index ad4950dc9..b16624add 100644 --- a/src/main/java/org/owasp/esapi/Encoder.java +++ b/src/main/java/org/owasp/esapi/Encoder.java @@ -96,7 +96,7 @@ * stores some untrusted data item such as an email address from a user. A * developer thinks "let's output encode this and store the encoded data in * the database, thus making the untrusted data safe to use all the time, thus -* saving all of us developers all the encoding troubles later on". On the surface, + * saving all of us developers all the encoding troubles later on". On the surface, * that sounds like a reasonable approach. The problem is how to know what * output encoding to use, not only for now, but for all possible future * uses? It might be that the current application code base is only using it in @@ -147,10 +147,28 @@ * target="_blank" rel="noopener noreferrer">ESAPI Encoder JUnittest cases for ideas. * If you are really ambitious, an excellent resource for XSS attack patterns is * BeEF - The Browser Exploitation Framework Project. + *
  • A final note on {@code Encoder} implementation details: + * Most of the {@code Encoder} methods make extensive use of ESAPI's {@link org.owasp.esapi.codecs.Codec} + * classes under-the-hood. These {@code Codec} classes are intended for use for encoding and decoding + * input based on some particular context or specification. While the OWASP team + * over the years have made every effort to be cautious--often going to extremes + * to make "safe harbor" decisions on harmful inputs other similar encoders assume are already safe + * (we did this to in order to protect the client's users from buggy browsers that don't adhere + * to the W3C HTML specications)&em;the various {@code Codec} implemtations can offer + * NO GUARANTEE of safety of the content being encoded or decoded. Therefore, + * it is highly advised to practice a security-in-depth approach for everything you do. + * By following that advice, you will minimize the impact and/or likelihood of any + * vulnerabilities from bugs in the ESAPI code or accidental misuse of the ESAPI + * library on your part. In particular, whenever there are cases where cients use + * any of these {@link org.owasp.esapi.codecs.Codec} classes directly, it is highly + * recommended to perform canonicalization followed by strict input valiation both + * prior to encoding and after decoding to protect your application from input-based + * attacks. *
  • * - * + *

    * @see OWASP Cross-Site Scripting Prevention Cheat Sheet + * @see org.owasp.esapi.Validator * @see OWASP Proactive Controls: C4: Encode and Escape Data * @see Properly encoding and escaping for the web * @author Jeff Williams (jeff.williams .at. owasp.org) @@ -215,7 +233,7 @@ public interface Encoder { * *

    * Using canonicalize is simple. The default is just... @@ -395,25 +413,79 @@ public interface Encoder { /** * Encode input for use in a SQL query, according to the selected codec - * (appropriate codecs include the MySQLCodec and OracleCodec). - * - * This method is not recommended. The use of the {@code PreparedStatement} - * interface is the preferred approach. However, if for some reason - * this is impossible, then this method is provided as a weaker - * alternative. - * - * The best approach is to make sure any single-quotes are double-quoted. - * Another possible approach is to use the {escape} syntax described in the - * JDBC specification in section 1.5.6. - * + * (appropriate codecs include the {@link org.owasp.esapi.codecs.MySQLCodec} + * and {@link org.owasp.esapi.codecs.OracleCodec}), but see + * "SECURITY WARNING" below before using. + *

    + * The this method attempts to ensure make sure any single-quotes are double-quoted + * (i.e., as '', not double-quotes, as in "). Another possible approach + * is to use the {escape} syntax described in the JDBC specification in section 1.5.6. * However, this syntax does not work with all drivers, and requires * modification of all queries. - * + *

    + * SECURITY WARNING: This method is NOT recommended. The use of the {@code PreparedStatement} + * interface is the preferred approach. However, if for some reason + * this is impossible, then this method is provided as a significantly weaker + * alternative. In particular, it should be noted that if all you do to + * address potential SQL Injection attacks is to use this method to escape + * parameters, you will fail miserably. According to the + * + * OWASP SQL Injection Prevention Cheat Sheet, these are the primary + * defenses against SQL Injection (as of June 2025): + *

    + *

    + * According to "Option 4" (which is what this method implements), that OWASP Cheat Sheet + * states: + *

    + * In this approach, the developer will escape all user input + * before putting it in a query. It is very database specific + * in its implementation. This methodology is frail compared + * to other defenses, and we CANNOT guarantee that this option + * will prevent all SQL injections in all situations. + *
    + * (Emphasis ours.) + *

    + * Note you could give yourself a slightly better chance at success if prior to + * escaping by this method, you first canonicalize the input and run it through + * some strong allow-list validation. We will not provide anymore details than + * that, lest we encourage its misuse; however, it should be noted that resorting + * to use this method--especially by itself--should rarely, if ever, used. It + * is intended as a last ditch, emergency, Hail Mary effort. (To be honest, you'd + * likely have more success setting up a WAF such as + * OWASP ModSecurity and + * OWASP CRS + * if you need a temporary emergency SQLi defense shield, but using {@code PreparedStatement} + * is still your best option if you have the time and resources. + *

    + * Note to AppSec / Security Auditor teams: If see this method being used in + * application code, the risk of an exploitable SQLi vulnerability is still high. We + * stress the importance of the first two Options discussed in the + * + * OWASP SQL Injection Prevention Cheat Sheet. If you allow this, we recommend only + * doing so for a limited time duration and in the meantime creating some sort of security + * exception ticket to track it. + *

    + * IMPORTANT NOTE: If you really do insist enabling leg cannon mode and use + * this method, then you MUST follow these instructions. Failure to do so will + * result in a {@link org.owasp.esapi.errors.NotConfiguredByDefaultException} being + * thrown when you try to call it. Thus to make it work, you need to add the implementation + * method corresponding to this interace (defined in the property "ESAPI.Encoder" + * (wihch defaults to "org.owasp.esapi.reference.DefaultEncoder") in your "ESAPI.properties" file, + * to the ESAPI property "ESAPI.dangerouslyAllowUnsafeMethods.methodNames". See + * the Security Bulletin #13 document referenced below for additional details. + *

    * @see JDBC Specification * @see java.sql.PreparedStatement + * @see ESAPI Security Bulletin #13 * * @param codec - * a Codec that declares which database 'input' is being encoded for (ie. MySQL, Oracle, etc.) + * a {@link org.owasp.esapi.codecs.Codec} that declares which database 'input' is being encoded for (ie. MySQL, Oracle, etc.) * @param input * the text to encode for SQL * @@ -526,7 +598,7 @@ public interface Encoder { * For more information, refer to this * article which specifies the following list of characters as the most - * dangerous: ^&"*';<>(). ( ) . This * paper suggests disallowing ' and " in queries. * diff --git a/src/main/java/org/owasp/esapi/PropNames.java b/src/main/java/org/owasp/esapi/PropNames.java index ab30e47fa..8aa4179a9 100644 --- a/src/main/java/org/owasp/esapi/PropNames.java +++ b/src/main/java/org/owasp/esapi/PropNames.java @@ -87,6 +87,8 @@ public final class PropNames { public static final String ADDITIONAL_ALLOWED_CIPHER_MODES = "Encryptor.cipher_modes.additional_allowed"; public static final String KDF_PRF_ALG = "Encryptor.KDF.PRF"; public static final String PRINT_PROPERTIES_WHEN_LOADED = "ESAPI.printProperties"; + public static final String ACCEPTED_UNSAFE_METHOD_NAMES = "ESAPI.dangerouslyAllowUnsafeMethods.methodNames"; + public static final String ACCEPTED_UNSAFE_METHODS_JUSTIFICATION = "ESAPI.dangerouslyAllowUnsafeMethods.justification"; public static final String WORKING_DIRECTORY = "Executor.WorkingDirectory"; public static final String APPROVED_EXECUTABLES = "Executor.ApprovedExecutables"; @@ -129,7 +131,7 @@ public final class PropNames { public static final String DISCARD_LOGSPECIAL = "org.owasp.esapi.logSpecial.discard"; /* - * Implementation Keys + * Implementation Keys for the various major ESAPI components. */ public static final String LOG_IMPLEMENTATION = "ESAPI.Logger"; public static final String AUTHENTICATION_IMPLEMENTATION = "ESAPI.Authenticator"; diff --git a/src/main/java/org/owasp/esapi/codecs/Codec.java b/src/main/java/org/owasp/esapi/codecs/Codec.java index 52c49c1e2..b46de6d5d 100644 --- a/src/main/java/org/owasp/esapi/codecs/Codec.java +++ b/src/main/java/org/owasp/esapi/codecs/Codec.java @@ -22,6 +22,17 @@ * and canonicalization. The design of these codecs allows for character-by-character decoding, which is * necessary to detect double-encoding and the use of multiple encoding schemes, both of which are techniques * used by attackers to bypass validation and bury encoded attacks in data. + *

    + * Other than the interfaces, very few of these concrete classes are intended to be used directly. + * Rather, most of them are used through implementations of the {@link org.owasp.esapi.Encoder} + * interface. While the OWASP team over the years have made every effort to be extra cautious, the + * various {@code Codec} implementations can offer NO GUARANTEE of safety if the client is + * using these {@code Codec} classes directly. Therefore, if the client is using + * these classes directly, it is highly advised to practice security-in-depth + * and also perform canonicalization, followed by strict input validation, both + * prior to encoding and after decoding, to protect your application from input-based + * attacks. + *

    * * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) Aspect Security @@ -30,6 +41,7 @@ * @author Matt Seil (mseil .at. owasp.org) * @since June 1, 2017 * @see org.owasp.esapi.Encoder + * @see org.owasp.esapi.Validator */ public interface Codec { /** diff --git a/src/main/java/org/owasp/esapi/codecs/DB2Codec.java b/src/main/java/org/owasp/esapi/codecs/DB2Codec.java index 8df61bc34..f57555571 100644 --- a/src/main/java/org/owasp/esapi/codecs/DB2Codec.java +++ b/src/main/java/org/owasp/esapi/codecs/DB2Codec.java @@ -14,7 +14,14 @@ /** - * Implementation of the Codec interface for DB2 strings. This function will only protect you from SQLi in limited situations. + * Implementation of the Codec interface for IBM Db2 strings. + * This function will only protect you from SQLi in limited situations. + * To improve your chances of success, you made also need to do some + * additional canonicalization and input validation first. Before using this class, + * please be sure to read the "SECURITY WARNING" in + * {@link org.owasp.esapi.Encoder#encodeForSQL} + * before using this particular {@link org.owasp.esapi.codecs.Codec} and raising your hope of finding + * a silver bullet to kill all the SQLi werewolves. * * @author Sivasankar Tanakala (stanakal@TRS.NYC.NY.US) * @since October 26, 2010 @@ -65,4 +72,4 @@ public Character decodeCharacter(PushbackString input) { return (Character.valueOf('\'')); } -} \ No newline at end of file +} diff --git a/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java b/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java index c507b0362..9154f8df8 100644 --- a/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java @@ -19,9 +19,16 @@ /** * Codec implementation which can be used to escape string literals in MySQL. - *
    - * Implementation accepts 2 Modes as identified by the OWASP Recommended - * escaping strategies: + * This function will only protect you from SQLi in limited situations. + * To improve your chances of success, you made also need to do some + * additional canonicalization and input validation first. Before using this class, + * please be sure to read the "SECURITY WARNING" in + * {@link org.owasp.esapi.Encoder#encodeForSQL} + * before using this particular {@link org.owasp.esapi.codecs.Codec} and raising your hope of finding + * a silver bullet to kill all the SQLi werewolves. + *

    + * This implementation accepts 2 {@code org.owasp.esapi.codes.MySQLCodec.Mode}s as identified + * by the OWASP recommended escaping strategies: *

      *
    • ANSI
      * Simply encode all ' (single tick) characters with '' (two single ticks)
    • @@ -29,19 +36,19 @@ *
    • Standard * *
      - *   NUL (0x00) --> \0  [This is a zero, not the letter O]
      - *   BS  (0x08) --> \b
      - *   TAB (0x09) --> \t
      - *   LF  (0x0a) --> \n
      - *   CR  (0x0d) --> \r
      - *   SUB (0x1a) --> \Z
      - *   "   (0x22) --> \"
      - *   %   (0x25) --> \%
      - *   '   (0x27) --> \'
      - *   \   (0x5c) --> \\
      - *   _   (0x5f) --> \_
      + *   NUL (0x00) --> \0  [This is a zero, not the letter O]
      + *   BS  (0x08) --> \b
      + *   TAB (0x09) --> \t
      + *   LF  (0x0a) --> \n
      + *   CR  (0x0d) --> \r
      + *   SUB (0x1a) --> \Z
      + *   "   (0x22) --> \"
      + *   %   (0x25) --> \%
      + *   '   (0x27) --> \'
      + *   \   (0x5c) --> \\
      + *   _   (0x5f) --> \_
        *   
      - * all other non-alphanumeric characters with ASCII values less than 256 --> \c + * all other non-alphanumeric characters with ASCII values less than 256 --> \c * where 'c' is the original non-alphanumeric character. *
      * diff --git a/src/main/java/org/owasp/esapi/codecs/OracleCodec.java b/src/main/java/org/owasp/esapi/codecs/OracleCodec.java index eb91a07ce..4cd946286 100644 --- a/src/main/java/org/owasp/esapi/codecs/OracleCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/OracleCodec.java @@ -18,10 +18,14 @@ /** - * Implementation of the Codec interface for Oracle strings. This function will only protect you from SQLi in the case of user data - * bring placed within an Oracle quoted string such as: - * - * select * from table where user_name=' USERDATA '; + * Implementation of the {@link org.owasp.esapi.codecs.Codec} interface for Oracle DB strings. + * This function will only protect you from SQLi in limited situations. + * To improve your chances of success, you made also need to do some + * additional canonicalization and input validation first. Before using this class, + * please be sure to read the "SECURITY WARNING" in + * {@link org.owasp.esapi.Encoder#encodeForSQL} + * before using this particular {@link org.owasp.esapi.codecs.Codec} and raising your hope of finding + * a silver bullet to kill all the SQLi werewolves. * * @see how-to-escape-single-quotes-in-strings * @@ -87,4 +91,4 @@ public Character decodeCharacter( PushbackSequence input ) { return( Character.valueOf( '\'' ) ); } -} \ No newline at end of file +} diff --git a/src/main/java/org/owasp/esapi/errors/NotConfiguredByDefaultException.java b/src/main/java/org/owasp/esapi/errors/NotConfiguredByDefaultException.java new file mode 100644 index 000000000..3c30dbfec --- /dev/null +++ b/src/main/java/org/owasp/esapi/errors/NotConfiguredByDefaultException.java @@ -0,0 +1,32 @@ +package org.owasp.esapi.errors; + +/** + * A {@code NotConfiguredByDefaultException} should be thrown when a method that + * is disabled by default is invoked. + *

      + + * See the ESAPI properties "ESAPI.dangerouslyAllowUnsafeMethods.methodNames" + * and "ESAPI.dangerouslyAllowUnsafeMethods.justification" in the + * ESAPI.properties file for additional details. + *

      + */ +public class NotConfiguredByDefaultException extends ConfigurationException { + + protected static final long serialVersionUID = 1L; + + public NotConfiguredByDefaultException(Exception e) { + super(e); + } + + public NotConfiguredByDefaultException(String s) { + super(s); + } + + public NotConfiguredByDefaultException(String s, Throwable cause) { + super(s, cause); + } + + public NotConfiguredByDefaultException(Throwable cause) { + super(cause); + } +} diff --git a/src/test/resources/esapi/ESAPI-test.properties b/src/test/resources/esapi/ESAPI-test.properties index 72dd9e50a..d46c2d34e 100644 --- a/src/test/resources/esapi/ESAPI-test.properties +++ b/src/test/resources/esapi/ESAPI-test.properties @@ -5,4 +5,4 @@ invalid_int_property=invalid int boolean_property=true boolean_yes_property=yes boolean_no_property=no -invalid_boolean_property=invalid boolean \ No newline at end of file +invalid_boolean_property=invalid boolean diff --git a/src/test/resources/esapi/ESAPI.properties b/src/test/resources/esapi/ESAPI.properties index 8ffc61f66..7327fbc85 100644 --- a/src/test/resources/esapi/ESAPI.properties +++ b/src/test/resources/esapi/ESAPI.properties @@ -578,3 +578,40 @@ Validator.AcceptLenientDates=false # #Validator.HtmlValidationAction=clean Validator.HtmlValidationAction=throw + +######################################################################################## +# The following methods are now disabled in the default configuration and must +# be explicity enabled. If you try to invoke a method disabled by default, ESAPI +# will thrown a NotConfiguredByDefaultException. +# +# The reason for this varies, but ranges from they are not really suitable for +# enterprise scale to that are only marginally tested (if at all) versus the are +# unsafe for general use, although them may be fine when combined with other +# security-in-depth techiques. +# +# The disabled-by-default methods are: +# org.owasp.esapi.reference.DefaultEncoder.encodeForSQL +# org.owasp.esapi.ESAPI.accessController [FUTURE] +# +# The format is a comma-separated list of fully.Qualified.ClassName.methodName; +# all class names must begin with "org.owasp.esapi.". +# +# Note to ESAPI Devs: There is presently NO WAY to specific which specific +# method to indicate here when the method name alone, +# absent from its signature, is ambiguous, so it is +# best to avoid those if at all possible! +# +# An example of that would be something like: +# org.owasp.esapi.reference.DefaultValidator.getValidPrintable +# which has 4 interfaces so currently, there's no way to +# specify a specific one. +# +# We need this there for our existing JUnit tests for encodeForSQL. Use an +# alternate ESAPI property config filen name for testing this aspect out. +ESAPI.dangerouslyAllowUnsafeMethods.methodNames=org.owasp.esapi.reference.DefaultEncoder.encodeForSQL + +# Normally you would put some text here (that will be logged) that provides some +# justification as to why you have enabled these functions. This can be +# anythuing such as a Jira or ServiceNow ticket number, a security exception +# reference, etc. If it is left empty, it will just like "Justification: none".` +ESAPI.enableLegCannonModeAndGetMyAssFired.justification=blah,blah. Please don't fire my @$$. Ticket # 12345 diff --git a/src/test/resources/esapi/new-props.properties b/src/test/resources/esapi/new-props.properties new file mode 100644 index 000000000..5dc3ab1c2 --- /dev/null +++ b/src/test/resources/esapi/new-props.properties @@ -0,0 +1,58 @@ +# For testing new properties part of PR# 886. Hoping these are the only +# properties that will be needed. TBD. + + +ESAPI.Encoder=org.owasp.esapi.reference.DefaultEncoder + +ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory +#=========================================================================== +# ESAPI Logging +# Set the application name if these logs are combined with other applications +Logger.ApplicationName=ExampleApplication +# If you use an HTML log viewer that does not properly HTML escape log data, you can set LogEncodingRequired to true +Logger.LogEncodingRequired=false +# Determines whether ESAPI should log the application name. This might be clutter in some single-server/single-app environments. +Logger.LogApplicationName=true +# Determines whether ESAPI should log the server IP and port. This might be clutter in some single-server environments. +Logger.LogServerIP=true +# Determines whether ESAPI should log the user info. +Logger.UserInfo=true +# Determines whether ESAPI should log the session id and client IP. +Logger.ClientInfo=true + +# Determines whether ESAPI should log the prefix of [EVENT_TYPE - APPLICATION NAME]. +# If all above Logger entries are set to false, as well as LogPrefix, then the output would be the same as if no ESAPI was used +Logger.LogPrefix=true + +################## NEW PROPERTIES ################### +# +# NOTE: I still like the property name +# ESAPI.enableLegCannonModeAndGetMyAssFired.methodNames" +# and +# ESAPI.enableLegCannonModeAndGetMyAssFired.methodNames" +# better. Betcha those would be set a lot less often than this "more +# professional" names will be. +# +######################################################################################## +# The following methods are now disabled in the default configuration and must +# be explicity enabled. If you try to invoke a method disabled by default, ESAPI +# will thrown a NotConfiguredByDefaultException. +# +# The reason for this varies, but ranges from they are not really suitable for +# enterprise scale to that are only marginally tested (if at all) versus the are +# unsafe for general use, although them may be fine when combined with other +# security-in-depth techiques. +# +# The disabled-by-default methods are: +# org.owasp.esapi.reference.DefaultEncoder.encodeForSQL +# org.owasp.esapi.ESAPI.accessController [FUTURE; will correspond to deprecation notice] +# +# The format is a comma-separated list of fully.Qualified.ClassName.methodName; +# all class names must begin with "org.owasp.esapi.". +ESAPI.dangerouslyAllowUnsafeMethods.methodNames= + +# Normally you would put some text here (that will be logged) that provides some +# justification as to why you have enabled these functions. This can be +# anythuing such as a Jira or ServiceNow ticket number, a security exception +# reference, etc. If it is left empty, it will just like "Justification: none".` +ESAPI.enableLegCannonModeAndGetMyAssFired.justification=