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 @@
* 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+ * This implementation accepts 2 {@code org.owasp.esapi.codes.MySQLCodec.Mode}s as identified + * by the OWASP recommended escaping strategies: *
- * 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) --> \_ ** 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
- * 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. *
+ + * 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=