diff --git a/documentation/ESAPI-security-bulletin13.odt b/documentation/ESAPI-security-bulletin13.odt new file mode 100644 index 000000000..8c26809d2 Binary files /dev/null and b/documentation/ESAPI-security-bulletin13.odt differ diff --git a/documentation/ESAPI-security-bulletin13.pdf b/documentation/ESAPI-security-bulletin13.pdf new file mode 100644 index 000000000..18a55f076 Binary files /dev/null and b/documentation/ESAPI-security-bulletin13.pdf differ diff --git a/documentation/esapi4java-core-2.7.0.0-release-notes.txt b/documentation/esapi4java-core-2.7.0.0-release-notes.txt new file mode 100644 index 000000000..f88656067 --- /dev/null +++ b/documentation/esapi4java-core-2.7.0.0-release-notes.txt @@ -0,0 +1,194 @@ +Release notes for ESAPI 2.7.0.0 + Release date: 2025-06-27 + Project leaders: + -Kevin W. Wall + -Matt Seil + +Previous release: ESAPI 2.6.2.0, 2025-06-02 + + +Executive Summary: Important Things to Note for this Release +------------------------------------------------------------ +This is a major patch release with the primary intent of addressing CVE-2025-5878. See https://nvd.nist.gov/vuln/detail/CVE-2025-5078 and especially Security Bulletin #13 (https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin13.pdf) for details. It also updates Apache Commons FileUploads to 1.6.0 to address CVE-2025-48976. That CVE likely does not affect the HTTP.getFileUloads interfaces (which is the only methods that use that library), but we have not had time to analyze it fully given the CVE cited against ESAPI. Apache Commons BeanUtils was also updated to 1.11.0 to address CVE-2025-48734 which potentially could anyone using ESAPI's AccessController and has placed their access control policy in a place where an attacker may be overwrite it. That is highly unlikely, but better safe than sorry. + +This 2.7.0.0 release also has significant Javadoc clarifications. Security Bulletin #13 explains why. + +If you fail to read Security Bulletin #13 and you are affected by CVE-2025-5878, your application using ESAPI 2.7.0.0 will not work, so it is VERY IMPORTANT that you read that. + +Notes if you are NOT updating from the immediate previous release. release 2.6.2.0: + * You need to read through the series of release notes FIRST, going in order. + * For example, if you were updating from an older ESAPI release (say, 2.3.0.0), you should go back and FIRST read all the subsequent release notes in turn. For instance, if you are currently on release 2.3.0.0 and upgrading to (say) release 2.x.y.z, you should MINIMALLY read the sections "Changes Requiring Special Attention" in each of the subsequent release notes. So, going from release 2.3.0.0 to 2.x.y.z, you should in turn, read: + + esapi4java-core-2.4.0.0-release-notes.txt + esapi4java-core-2.5.0.0-release-notes.txt + esapi4java-core-2.5.1.0-release-notes.txt + esapi4java-core-2.5.2.0-release-notes.txt + ...etc., up through the current set of release notes... + esapi4java-core-2.x.y.z-release-notes.txt + +in that order. YOU HAVE BEEN WARNED!!! (These release notes are too large to put all this in a given document; very few read them thoroughly as it is.) + +If your SCA tool is reporting any CVE from a direct or transitive dependency in ESAPI, before reporting it as an GitHub issue, please make sure that you review the vulnerability analysis written up in https://github.com/ESAPI/esapi-java-legacy/blob/develop/Vulnerability-Summary.md. Please email us or contact us in our GitHub Discussions page if you have questions about this. See also the SECURITY.md file to report any security issues with ESAPI. + +You are encouraged to review the vulnerability analysis written up in https://github.com/ESAPI/esapi-java-legacy/blob/develop/Vulnerability-Summary.md and email us or contact us in our GitHub Discussions page if you have questions. + + +================================================================================================================= + +Basic ESAPI facts +----------------- + +ESAPI 2.6.2.0 release: + 207 Java source files + 4312 JUnit tests in 133 Java source files + +ESAPI 2.7.0.0 release: + 208 Java source files + 4312 JUnit tests in 134 Java source files + +1 GitHub Issues closed in this release, including those we've decided not to fix (marked 'wontfix' and 'falsepositive'). +(Reference: https://github.com/ESAPI/esapi-java-legacy/issues?q=is%3Aissue+state%3Aclosed+updated%3A%3E%3D2025-06-02) + +Issue # GitHub Issue Title +---------------------------------------------------------------------------------------------- +883 Update Apache Commons BeanUtils from 1.9.4 to 1.11.0 to address CVE-2025-48734 + +----------------------------------------------------------------------------- + + Changes Requiring Special Attention + +----------------------------------------------------------------------------- + +IMPORTANT: Read Security Bulletin #13 (https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/ESAPI-security-bulletin13.pdf) + +Important JDK Support Announcement +* ESAPI 2.3.0.0 was the last Java release to support Java 7. ESAPI 2.4.0 requires using Java 8 or later. See the ESAPI 2.4.0.0 release notes (https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.4.0.0-release-notes.txt) for details as to the reason. + - This means if your project requires Java 7, you must use ESAPI 2.3.0.0 or earlier. + +Important ESAPI Logging Changes + +* Since ESAPI 2.5.0.0, support for logging directly via Log4J 1 has been removed. (This was two years after it having first been deprecated.) Thus, you only choice of ESAPI logging are + - java.util.logging (JUL), which as been the default since ESAPI 2.2.1.0. + * Set ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory in your ESAPI.properties file. + - SLF4J (which your choice of supported SLF4J logging implementation) + * Set ESAPI.Logger=org.owasp.esapi.logging.slf4j.Slf4JLogFactory in your ESAPI.properties file. +* Logger configuration notes - If you are migrating from prior to ESAPI 2.2.1.1, you will need to update your ESAPI.properties file as logging-related configuration as per the ESAPI 2.2.1.1 release notes, which may be found at: + https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/esapi4java-core-2.2.1.1-release-notes.txt#L39-L78 + +If you use ESAPI 2.5.0.0 or later, you will get an ClassNotFoundException as the root cause if you still have your ESAPI.Logger property set to use Log4J because the org.owasp.esapi.logger.log4j.Log4JFactory class has been completely removed from the ESAPI jar. If you are dead set on continuing to use Log4J 1, you ought to be able to do so via SLF4J. The set up for Log4J 1 (which has not be tested), should be similar to configure ESAPI to use SLF4J with Log4J 2 as described here: + https://github.com/ESAPI/esapi-java-legacy/wiki/Using-ESAPI-with-SLF4J#slf4j-using-log4j-2x + +----------------------------------------------------------------------------- + + Remaining Known Issues / Problems + +----------------------------------------------------------------------------- +None known, other than the remaining open issues on GitHub. + +----------------------------------------------------------------------------- + + Other changes in this release, some of which not tracked via GitHub issues + +----------------------------------------------------------------------------- + +* Changes since last release 2.6.2.0 and 2.7.0.0, i.e., changes between 2025-06-02 and 2025-06-27). + + Note: I am no longer going to provide the 'Developer Activity Report' that I used to this manually create in tabular form. This is in part because I use to use 'mvn site' to assist with its creation, but neither the 'Developer Activity' nor 'File Activity' sections of the 'mvn site' output is currently working. + + That said, I don't care as this was always a major PITA and I think it had dubious value to start with. + + Therefore, I am replacing it to a stock GitHub tag comparison of the current and previous release, which I can automate. + + Please see, + + https://github.com/ESAPI/esapi-java-legacy/compare/esapi-...esapi-2.7.0.0 + + for details. It contains all the information that the previous 'Developer Activity Reports' did and then some. + +----------------------------------------------------------------------------- + +CHANGELOG: Create your own. May I suggest: + + git log --stat --since=2025-06-02 --reverse --pretty=medium + + which will show all the commits since just after the previous (2.6.2.0) release. + + Alternately, you can download the most recent ESAPI source and run + + mvn site + + which will create a CHANGELOG file named 'target/site/changelog.html' + + +----------------------------------------------------------------------------- + +Direct and Transitive Runtime and Test Dependencies: + + $ mvn -B dependency:tree + ... + [INFO] --- maven-dependency-plugin:3.8.1:tree (default-cli) @ esapi --- + [INFO] org.owasp.esapi:esapi:jar:2.7.0.0-SNAPSHOT + [INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided + [INFO] +- javax.servlet.jsp:javax.servlet.jsp-api:jar:2.3.3:provided + [INFO] +- xom:xom:jar:1.3.9:compile + [INFO] +- commons-beanutils:commons-beanutils:jar:1.11.0:compile + [INFO] | +- commons-logging:commons-logging:jar:1.3.5:compile + [INFO] | \- commons-collections:commons-collections:jar:3.2.2:compile + [INFO] +- commons-configuration:commons-configuration:jar:1.10:compile + [INFO] +- commons-lang:commons-lang:jar:2.6:compile + [INFO] +- commons-fileupload:commons-fileupload:jar:1.6.0:compile + [INFO] +- org.apache.commons:commons-collections4:jar:4.5.0-M2:compile + [INFO] +- org.apache-extras.beanshell:bsh:jar:2.0b6:compile + [INFO] +- org.owasp.antisamy:antisamy:jar:1.7.8:compile + [INFO] | +- commons-io:commons-io:jar:2.19.0:compile + [INFO] | +- org.apache.httpcomponents.client5:httpclient5:jar:5.4.4:compile + [INFO] | | \- org.apache.httpcomponents.core5:httpcore5-h2:jar:5.3.4:compile + [INFO] | +- org.apache.httpcomponents.core5:httpcore5:jar:5.3.4:compile + [INFO] | +- org.apache.xmlgraphics:batik-css:jar:1.19:compile + [INFO] | | +- org.apache.xmlgraphics:batik-shared-resources:jar:1.19:compile + [INFO] | | +- org.apache.xmlgraphics:batik-util:jar:1.19:compile + [INFO] | | | +- org.apache.xmlgraphics:batik-constants:jar:1.19:compile + [INFO] | | | \- org.apache.xmlgraphics:batik-i18n:jar:1.19:compile + [INFO] | | \- org.apache.xmlgraphics:xmlgraphics-commons:jar:2.11:compile + [INFO] | +- org.htmlunit:neko-htmlunit:jar:4.11.0:compile + [INFO] | +- xerces:xercesImpl:jar:2.12.2:compile + [INFO] | \- xml-apis:xml-apis-ext:jar:1.3.04:compile + [INFO] +- org.slf4j:slf4j-api:jar:2.0.16:compile + [INFO] +- xml-apis:xml-apis:jar:1.4.01:compile + [INFO] +- com.github.spotbugs:spotbugs-annotations:jar:4.9.3:compile (optional) + [INFO] | \- com.google.code.findbugs:jsr305:jar:3.0.2:compile (optional) + [INFO] +- commons-codec:commons-codec:jar:1.17.1:test + [INFO] +- junit:junit:jar:4.13.2:test + [INFO] +- org.bouncycastle:bcprov-jdk18on:jar:1.78.1:test + [INFO] +- org.hamcrest:hamcrest-core:jar:2.2:test + [INFO] | \- org.hamcrest:hamcrest:jar:2.2:test + [INFO] +- org.powermock:powermock-api-mockito2:jar:2.0.9:test + [INFO] | \- org.powermock:powermock-api-support:jar:2.0.9:test + [INFO] +- org.mockito:mockito-core:jar:3.12.4:test + [INFO] | +- net.bytebuddy:byte-buddy:jar:1.11.13:test + [INFO] | +- net.bytebuddy:byte-buddy-agent:jar:1.11.13:test + [INFO] | \- org.objenesis:objenesis:jar:3.2:test + [INFO] +- org.powermock:powermock-core:jar:2.0.9:test + [INFO] | \- org.javassist:javassist:jar:3.27.0-GA:test + [INFO] +- org.powermock:powermock-module-junit4:jar:2.0.9:test + [INFO] | \- org.powermock:powermock-module-junit4-common:jar:2.0.9:test + [INFO] +- org.powermock:powermock-reflect:jar:2.0.9:test + [INFO] \- org.openjdk.jmh:jmh-core:jar:1.37:test + [INFO] +- net.sf.jopt-simple:jopt-simple:jar:5.0.4:test + [INFO] \- org.apache.commons:commons-math3:jar:3.6.1:test + [INFO] ------------------------------------------------------------------------ + +----------------------------------------------------------------------------- + +Acknowledgments: + A whole bunch of folks to thank this time: + - Longlong Gong (uglory-gll) - The security researcher who discovered the vulnerability that became CVE-2025-5878. + Most people curse those who find CVEs in their software, but because of Longlong's work, we feel ESAPI is a better library and has a more secure future. (See the "Lessons Learned" section of Security Bulletin #13 for an explanation.) + - The VulDB CNA team. + - In no particular order, Jeff Williams, Matt Seil, Jeremiah Stacey, Erika von Kampen, Bill Sempf, and Ken Pyle, all who provided me with excellent feedback on the documentation and code changes and help me keep my sanity for the past 3 weeks. + - My wife for tolerating my long evenings for the past 3 weeks. I know I've been cranky and it's been stressful for us both, but thanks for being so understanding and supportive. + - And finally, thanks to all the ESAPI users who make this worthwhile. This is for you. + +A special thanks to the ESAPI community from the ESAPI project co-leaders: + Kevin W. Wall (kwwall) <== The irresponsible party for these release notes! + Matt Seil (xeno6696) diff --git a/pom.xml b/pom.xml index e69d57aa4..e43fd6c7a 100644 --- a/pom.xml +++ b/pom.xml @@ -135,13 +135,13 @@ 2.0.0-M11 2.0.9 4.9.3 - 4.9.3.0 + 4.9.3.1 3.5.3 1.8 - 2025-05-19 00:00:00 + 2025-06-02 00:00:00 @@ -221,7 +221,7 @@ commons-fileupload commons-fileupload - 1.5 + 1.6.0 @@ -664,7 +664,7 @@ org.apache.maven.plugins maven-pmd-plugin - 3.26.0 + 3.27.0 diff --git a/scripts/vars.2.7.0.0 b/scripts/vars.2.7.0.0 new file mode 100644 index 000000000..829c1663c --- /dev/null +++ b/scripts/vars.2.7.0.0 @@ -0,0 +1,14 @@ +# Do NOT edit this file directly. It will be created by the new createVarsFile.sh script, +# which should be run prior to the newReleaseNotes.sh script. + +# ESAPI (new / current) version +VERSION=2.7.0.0 + +# Previous ESAPI version +PREV_VERSION=2.6.2.0 + +# Release date of current version in yyyy-mm-dd format +YYYY_MM_DD_RELEASE_DATE=2025-06-27 + +# Previous ESAPI release date in same format +PREV_RELEASE_DATE=2025-06-02 diff --git a/src/main/java/org/owasp/esapi/ESAPI.java b/src/main/java/org/owasp/esapi/ESAPI.java index c42a21ff8..55e4d896d 100644 --- a/src/main/java/org/owasp/esapi/ESAPI.java +++ b/src/main/java/org/owasp/esapi/ESAPI.java @@ -16,10 +16,13 @@ */ package org.owasp.esapi; +import java.util.Arrays; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.owasp.esapi.util.ObjFactory; +import org.owasp.esapi.errors.ConfigurationException; /** * ESAPI locator class is provided to make it easy to gain access to the current ESAPI classes in use. @@ -93,16 +96,18 @@ public static Authenticator authenticator() { } /** - * The ESAPI Encoder is primarily used to provide output encoding to + * The ESAPI {@code Encoder} is primarily used to provide output encoding to * prevent Cross-Site Scripting (XSS). - * @return the current ESAPI Encoder object being used to encode and decode data for this application. + * @return the current ESAPI {@code Encoder} object being used to encode and decode data for this application. */ public static Encoder encoder() { return ObjFactory.make( securityConfiguration().getEncoderImplementation(), "Encoder" ); } /** - * @return the current ESAPI Encryptor object being used to encrypt and decrypt data for this application. + * ESAPI {@code Encryptor} provides a set of methods for performing common encryption, random number, and + * hashing operations. + * @return the current ESAPI {@code Encryptor} object being used to encrypt and decrypt data for this application. */ public static Encryptor encryptor() { return ObjFactory.make( securityConfiguration().getEncryptionImplementation(), "Encryptor" ); @@ -221,4 +226,74 @@ public static String initialize( String impl ) { public static void override( SecurityConfiguration config ) { overrideConfig = config; } + + // KWW - OPEN ISSUE: I don't like placing this here, but it's convenient and I + // don't really know a better place for it and would rather not create + // a whole new utility class just to use it. + /** + * Determine if a given fully qualified (ESAPI) method name has been explicitly + * enabled in the ESAPI.properties's file via the property name + * ESAPI.dangerouslyAllowUnsafeMethods.methodNames. Note that there + * is no real reason for an ESAPI client to use this, It is intended for + * interal use, + *

+ * The reason this method exists is because certain (other) ESAPI method names + * are considered "unsafe" and therefore should be used with extra caution. + * These "unsafe" methods may include methods that are: + *

    + *
  • Deprecated and thus no longer suggested for long term use.
  • + *
  • Methods where the programming contract is not in itself sufficient to ensure safety alone + * and developers are expected to take addional actions on their own to secure their application.
  • + *
  • Methods that are using some unpatched transitive dependency that we haven't firmly + * established grounds for it not being exploitable in the manner that ESAPI uses it.
  • + *
  • Methods whose reference implementations are not scalable to the enterprise level.
  • + *
+ * Public methods that are not in that list for the above ESAPI property + * are generally are considered enabled and okay to use unless their Javadoc + * indicates otherwise. + *

+ * Note that this method is intended primarilly for internal ESAPI use and if we were + * using Java Modules (in JDK 9 and later), this method would not be exported. + *

+ * For further details, please see the ESAPI GitHub wiki article, + * "Reducing the ESAPI Library's Attack Surface". + * @param fullyQualifiedMethodName A fully qualified ESAPI class name (so, should start + * "org.owasp.esapi.") followed by the method name (but without + * parenthesis or any parameter signature information. + * @return {@code true} if the parameter {@code fullyQualifiedMethodName} is in the comma-separated + * list of values in the ESAPI property ESAPI.dangerouslyAllowUnsafeMethods.methodNames, + * otherwise {@code false} is returned. + */ + public static boolean isMethodExplicityEnabled(String fullyQualifiedMethodName) { + if ( fullyQualifiedMethodName == null || fullyQualifiedMethodName.trim().isEmpty() ) { + throw new IllegalArgumentException("Program error: fullyQualifiedMethodName parameter cannot be null or empty"); + } + String desiredMethodName = fullyQualifiedMethodName.trim(); + // This regex is too liberal to be anything more than just a trivial + // sanity test to protect against typos. + if ( !desiredMethodName.matches("^org\\.owasp\\.esapi\\.(\\p{Alnum}|\\.)*$") ) { + throw new IllegalArgumentException("Program error: fullyQualifiedMethodName must start with " + + "'org.owasp.esapi.' and be a valid method name."); + } + + String enabledMethods = null; + try { + // Need to do this w/in a try/catch because if the property is not + // found, getStringProp will throw a ConfigurationException rather + // than returning a null. + enabledMethods = securityConfiguration().getStringProp("ESAPI.dangerouslyAllowUnsafeMethods.methodNames"); + } catch( ConfigurationException cex ) { + return false; // Property not found at all. + } + + + // Split it up by ',' and then filter it by finding the first on that + // matches the desired method name passed in as the method parameter. + // If no matches, return the empty string. + String result = Arrays.stream( enabledMethods.trim().split(",") ) + .filter(methodName -> methodName.trim().equals( desiredMethodName ) ) + .findFirst() + .orElse(""); + return !result.isEmpty(); + } } diff --git a/src/main/java/org/owasp/esapi/Encoder.java b/src/main/java/org/owasp/esapi/Encoder.java index b16624add..409b27b24 100644 --- a/src/main/java/org/owasp/esapi/Encoder.java +++ b/src/main/java/org/owasp/esapi/Encoder.java @@ -472,7 +472,7 @@ public interface Encoder { * 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 + * 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" @@ -490,8 +490,14 @@ public interface Encoder { * the text to encode for SQL * * @return input encoded for use in SQL + * @see + * ESAPI Security Bulletin #13 + * @deprecated This method is considered dangerous and not easily made safe and thus under strong + * consideration to be removed within 1 years time after the 2.7.0.0 release. Please + * see the referenced ESAPI Security Bulletin #13 for further details. */ - String encodeForSQL(Codec codec, String input); + @Deprecated + String encodeForSQL(Codec codec, String input); /** * Encode for an operating system command shell according to the selected codec (appropriate codecs include the WindowsCodec and UnixCodec). diff --git a/src/main/java/org/owasp/esapi/codecs/DB2Codec.java b/src/main/java/org/owasp/esapi/codecs/DB2Codec.java index f57555571..61d1f70cd 100644 --- a/src/main/java/org/owasp/esapi/codecs/DB2Codec.java +++ b/src/main/java/org/owasp/esapi/codecs/DB2Codec.java @@ -26,7 +26,13 @@ * @author Sivasankar Tanakala (stanakal@TRS.NYC.NY.US) * @since October 26, 2010 * @see org.owasp.esapi.Encoder + * @see + * ESAPI Security Bulletin #13 + * @deprecated This class is considered dangerous and not easily made safe and thus under strong + * consideration to be removed within 1 years time after the 2.7.0.0 release. Please + * see the referenced ESAPI Security Bulletin #13 for further details. */ +@Deprecated public class DB2Codec extends AbstractCharacterCodec { public String encodeCharacter(char[] immune, Character c) { diff --git a/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java b/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java index 9154f8df8..bd2829521 100644 --- a/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java @@ -63,7 +63,13 @@ * MySQL 8.0 String Literals * OWASP * SQL_Injection_Prevention_Cheat_Sheet#MySQL_Escaping + * @see + * ESAPI Security Bulletin #13 + * @deprecated This class is considered dangerous and not easily made safe and thus under strong + * consideration to be removed within 1 years time after the 2.7.0.0 release. Please + * see the referenced ESAPI Security Bulletin #13 for further details. */ +@Deprecated public class MySQLCodec extends AbstractCharacterCodec { /** * Specifies the SQL Mode the target MySQL Server is running with. For details about MySQL Server Modes diff --git a/src/main/java/org/owasp/esapi/codecs/OracleCodec.java b/src/main/java/org/owasp/esapi/codecs/OracleCodec.java index 4cd946286..2746f9137 100644 --- a/src/main/java/org/owasp/esapi/codecs/OracleCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/OracleCodec.java @@ -20,20 +20,44 @@ /** * 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 + * To improve your chances of success, you may also need to do some * additional canonicalization and input validation first. Before using this class, - * please be sure to read the "SECURITY WARNING" in + * 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 - * + *

+ * CAUTION: This class has some known issues. During the investigation of + * CVE-2025-5878, it was discovered that since this class' inception in + * 2007, that Oracle databases also use \ (backslash) as a default escape char. + * That was fundamental in the vulnerability, since the escape character itself + * was not being escaped. We had originally planned to address this, but while + * researching the issue, we discovered that not only was there a new default + * escape character for Oracle SQL*Plus, but that developers could actually + * override the default to a character of their choosing. (For details see + * SET ESCAPE + * and + * How to Escape Characters in Oracle PL/SQL Queries.) The second instance is + * especially scary, since it illustrates how a developer can potentially can + * the default escape character as part of an ordinary SQL statement. We + * realized that there is no way we can defend against this, so it seemed + * pointless to even bother to try to quote default escape character passed in + * as input when {@code OracleCodec} is used with the {@code Encoder.encodeForSQL} + * interface. Therefore, you really should not use this, but if dead set in + * still using this leg canon, it;s on you. You have been warned. + *

+ * @see org.owasp.esapi.Encoder + * @see + * ESAPI Security Bulletin #13 * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) Aspect Security * @author Jim Manico (jim@manico.net) Manico.net * @since June 1, 2007 - * @see org.owasp.esapi.Encoder + * @see how-to-escape-single-quotes-in-strings + * @deprecated This class is considered dangerous and not easily made safe and thus under strong + * consideration to be removed within 1 years time after the 2.7.0.0 release. Please + * see the referenced ESAPI Security Bulletin #13 for further details. */ +@Deprecated public class OracleCodec extends AbstractCharacterCodec { diff --git a/src/main/java/org/owasp/esapi/errors/NotConfiguredByDefaultException.java b/src/main/java/org/owasp/esapi/errors/NotConfiguredByDefaultException.java index 3c30dbfec..58a0cbc98 100644 --- a/src/main/java/org/owasp/esapi/errors/NotConfiguredByDefaultException.java +++ b/src/main/java/org/owasp/esapi/errors/NotConfiguredByDefaultException.java @@ -13,20 +13,22 @@ public class NotConfiguredByDefaultException extends ConfigurationException { protected static final long serialVersionUID = 1L; + private static final String defaultMsg = "Unknown unsafe ESAPI method invoked without being explicitly allowed. " + + "Check exception stack trace for method name."; public NotConfiguredByDefaultException(Exception e) { super(e); } public NotConfiguredByDefaultException(String s) { - super(s); + super( (s == null || s.trim().isEmpty()) ? defaultMsg : s); } public NotConfiguredByDefaultException(String s, Throwable cause) { - super(s, cause); + super( (s == null || s.trim().isEmpty()) ? defaultMsg : s, cause); } public NotConfiguredByDefaultException(Throwable cause) { - super(cause); + super(defaultMsg, cause); } } diff --git a/src/main/java/org/owasp/esapi/logging/appender/ClientInfoSupplier.java b/src/main/java/org/owasp/esapi/logging/appender/ClientInfoSupplier.java index cfb8bea61..21d0955c8 100644 --- a/src/main/java/org/owasp/esapi/logging/appender/ClientInfoSupplier.java +++ b/src/main/java/org/owasp/esapi/logging/appender/ClientInfoSupplier.java @@ -15,8 +15,7 @@ package org.owasp.esapi.logging.appender; -// Uncomment and use once ESAPI supports Java 8 as the minimal baseline. -// import java.util.function.Supplier; +import java.util.function.Supplier; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @@ -28,7 +27,7 @@ * Supplier which can provide a String representing the client-side connection * information. */ -public class ClientInfoSupplier // implements Supplier +public class ClientInfoSupplier implements Supplier { /** Default Last Host string if the Authenticated user is null.*/ private static final String DEFAULT_LAST_HOST = "#UNKNOWN_HOST#"; diff --git a/src/main/java/org/owasp/esapi/logging/appender/EventTypeLogSupplier.java b/src/main/java/org/owasp/esapi/logging/appender/EventTypeLogSupplier.java index 93d3bd416..0788d558c 100644 --- a/src/main/java/org/owasp/esapi/logging/appender/EventTypeLogSupplier.java +++ b/src/main/java/org/owasp/esapi/logging/appender/EventTypeLogSupplier.java @@ -15,8 +15,7 @@ package org.owasp.esapi.logging.appender; -// Uncomment and use once ESAPI supports Java 8 as the minimal baseline. -// import java.util.function.Supplier; +import java.util.function.Supplier; import org.owasp.esapi.Logger; import org.owasp.esapi.Logger.EventType; @@ -26,7 +25,7 @@ * an EventType for logging * */ -public class EventTypeLogSupplier // implements Supplier +public class EventTypeLogSupplier implements Supplier { /** EventType reference to supply log representation of. */ private final EventType eventType; diff --git a/src/main/java/org/owasp/esapi/logging/appender/ServerInfoSupplier.java b/src/main/java/org/owasp/esapi/logging/appender/ServerInfoSupplier.java index 8d62a58f0..88cc786b8 100644 --- a/src/main/java/org/owasp/esapi/logging/appender/ServerInfoSupplier.java +++ b/src/main/java/org/owasp/esapi/logging/appender/ServerInfoSupplier.java @@ -15,8 +15,7 @@ package org.owasp.esapi.logging.appender; -// Uncomment and use once ESAPI supports Java 8 as the minimal baseline. -// import java.util.function.Supplier; +import java.util.function.Supplier; import javax.servlet.http.HttpServletRequest; @@ -26,7 +25,7 @@ * Supplier which can provide a String representing the server-side connection * information. */ -public class ServerInfoSupplier // implements Supplier +public class ServerInfoSupplier implements Supplier { /** Whether to log the server connection info. */ private boolean logServerIP = true; diff --git a/src/main/java/org/owasp/esapi/logging/appender/UserInfoSupplier.java b/src/main/java/org/owasp/esapi/logging/appender/UserInfoSupplier.java index 445be3dc2..bf5fd731c 100644 --- a/src/main/java/org/owasp/esapi/logging/appender/UserInfoSupplier.java +++ b/src/main/java/org/owasp/esapi/logging/appender/UserInfoSupplier.java @@ -15,8 +15,7 @@ package org.owasp.esapi.logging.appender; -// Uncomment and use once ESAPI supports Java 8 as the minimal baseline. -// import java.util.function.Supplier; +import java.util.function.Supplier; import org.owasp.esapi.ESAPI; import org.owasp.esapi.User; @@ -25,7 +24,7 @@ * Supplier which can provide a String representing the client-side connection * information. */ -public class UserInfoSupplier // implements Supplier +public class UserInfoSupplier implements Supplier { /** Default UserName string if the Authenticated user is null.*/ private static final String DEFAULT_USERNAME = "#ANONYMOUS#"; diff --git a/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java b/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java index 348cb4a4d..2b87e0d34 100644 --- a/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java +++ b/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java @@ -45,6 +45,11 @@ import org.owasp.esapi.codecs.JSONCodec; import org.owasp.esapi.errors.EncodingException; import org.owasp.esapi.errors.IntrusionException; +import org.owasp.esapi.errors.ConfigurationException; +import org.owasp.esapi.errors.NotConfiguredByDefaultException; + +import static org.owasp.esapi.PropNames.ACCEPTED_UNSAFE_METHOD_NAMES; +import static org.owasp.esapi.PropNames.ACCEPTED_UNSAFE_METHODS_JUSTIFICATION; /** @@ -271,11 +276,80 @@ public String encodeForVBScript(String input) { return vbScriptCodec.encode(IMMUNE_VBSCRIPT, input); } + /////////////////////////////////////////////////////////////////////// + // TODO - Move this method to some utility class (where?) when we + // are ready to use it on other methods than just encodeForSQL. + // + // At that time, also move the method ESAPI.isMethodExplicityEnabled + // to the same utility class. + /** + * Utility class to throw {@code NotConfiguredByDefaultException} if the + * specified method name is not enabled by default. + * + * @param fullyQualifiedMethodName is the method name that we are checkig if + * enabled in ESAPI.properties. + * @param customAuditMsg is a audit message to log and use in exceptions. If + * this value passed in is {@code null} or the string + * "<default>", then a canned message is used to + * compose the error message. + * @param seeAlso is a string that provides additional reference for context + * such as a CVE ID, GHAS Security Advisory, or ESAPI Security Bulletin. + * @throws NotConfiguredByDefaultException if the specified method name is + * not listed in the property ESAPI.dangerouslyAllowUnsafeMethods.methodNames + * in the ESAPI.properties file. + */ + private void ensureDangerousMethodExplicitlyEnabled(String fullyQualifiedMethodName, + String customAuditMsg, + String seeAlso) { + + String auditMsg = null; + if ( customAuditMsg == null || customAuditMsg.equalsIgnoreCase("") ) { + // Special case. Compose an audit message from a canned template. + // TODO: Null / empty check for 'seeAlso'. + auditMsg = "SIEM ALERT: Method '" + fullyQualifiedMethodName + "' has been invoked despite having credible " + + "security concerns; for additional details, see " + seeAlso + "."; + } else { + auditMsg = customAuditMsg; // Use the custom audit message + } + + if ( ! ESAPI.isMethodExplicityEnabled( fullyQualifiedMethodName ) ) { + throw new NotConfiguredByDefaultException( "Method not explicitly enabled in property " + + ACCEPTED_UNSAFE_METHOD_NAMES + "; " + auditMsg ); + } else { + String justification = null; + try { + // This throws a ConfigurationException (rather than returning null if + // the property name is not found so we need to handle that. + justification = ESAPI.securityConfiguration().getStringProp( ACCEPTED_UNSAFE_METHODS_JUSTIFICATION ); + } catch ( ConfigurationException cex ) { + logger.debug( Logger.EVENT_FAILURE, "Property " + ACCEPTED_UNSAFE_METHODS_JUSTIFICATION + " not found."); + justification = "None"; + } + + if ( justification == null || justification.trim().isEmpty() ) { + justification = "None"; + } + logger.warning( Logger.SECURITY_FAILURE, auditMsg + " Provided justification: " + justification ); + } + return; + } + /** * {@inheritDoc} + * + * @deprecated This method is considered dangerous and not easily made safe and thus under strong + * consideration to be removed within 1 years time after the 2.7.0.0 release. Please + * see the referenced ESAPI Security Bulletin #13 for further details. */ + @Deprecated public String encodeForSQL(Codec codec, String input) { + + // This will throw if this method is not explicitly enabled in ESAPI.properties. + ensureDangerousMethodExplicitlyEnabled( DefaultEncoder.class.getName() + ".encodeForSQL", + "", + "see CVE-2025-5878 and ESAPI Security Bulletin #13 for details" ); + if( input == null ) { return null; } diff --git a/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java b/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java index eb561349b..7b622c32d 100644 --- a/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java +++ b/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java @@ -43,29 +43,59 @@ import org.owasp.esapi.errors.ConfigurationException; /** - * The reference {@code SecurityConfiguration} manages all the settings used by the ESAPI in a single place. In this reference - * implementation, resources can be put in several locations, which are searched in the following order: + * Thse reference implementation class for {@code SecurityConfiguration} manages all the settings used by the ESAPI + * in a single place. In this reference implementation, resources can be put in several locations, which are + * searched in the following order: *

- * 1) Inside a directory set with a call to SecurityConfiguration.setResourceDirectory( "C:\temp\resources" ). - *

- * 2) Inside the System.getProperty( "org.owasp.esapi.resources" ) directory. + *

    + *
  1. + * Inside a directory set with a call to SecurityConfiguration.setResourceDirectory( "C:\temp\resources" ). + *

    + * CAUTION: Generally this technique should be avoided if you are + * using ESAPI in a resusable library, as it makes it very difficult for an + * application using your library to use its own version of + * ESAPI.properties. + *

    + * The only exception might be if you are writing a wrapper library for ESAPI + * and wish to provide a set of ESAPI properties that the application cannot accidentally + * change. However, selecting this option won't intentionally prevent changing ESAPI.properties + * unless you are signing the jar * and somehow forcing the verifiction of its digital signature at + * runtime. That's because it's easy enough to unjar your library, edit the ESAPI.properties + * file and then re-jar the library. + *

    + * This option was probably more intended for use by web applications by embedding + * them as resources in .war or .ear files, possibly with the intent of + * dissauding operations staff from making "improvements", a practice which + * makes much less--if any--sense in the era of DevOps and DevSecOps. + *

    + *
  2. + *
  3. + * Inside the {@code System.getProperty( "org.owasp.esapi.resources" )} directory. * You can set this on the java command line as follows (for example): *
    - *         java -Dorg.owasp.esapi.resources="C:\temp\resources"
    + *
    + *         java -Dorg.owasp.esapi.resources="C:\apps\myApp\resources"
      * 
    * You may have to add this to the start-up script that starts your web server. For example, for Tomcat, * in the "catalina" script that starts Tomcat, you can set the JAVA_OPTS variable to the {@code -D} string above. - *

    - * 3) Inside the {@code System.getProperty( "user.home" ) + "/.esapi"} directory (supported for backward compatibility) or + *

  4. + *
  5. + * Inside the {@code System.getProperty( "user.home" ) + "/.esapi"} directory (supported for backward compatibility) or * inside the {@code System.getProperty( "user.home" ) + "/esapi"} directory. - *

    - * 4) The first ".esapi" or "esapi" directory on the classpath. (The former for backward compatibility.) - *

    - * Once the Configuration is initialized with a resource directory, you can edit it to set things like master - * keys and passwords, logging locations, error thresholds, and allowed file extensions. - *

    - * WARNING: Do not forget to update ESAPI.properties to change the master key and other security critical settings. - *

    + *

  6. + *
  7. + * The first ".esapi" or "esapi" directory on the classpath. (The former for backward compatibility.) + *
  8. + *
+ *

+ * Once the ESAPI configuration is initialized with a resource directory, you can edit it to set things like master + * keys and passwords, logging locations, error thresholds, and allowed file extensions. (But see the above cautionary + * note if you are using ESAPI in a reusable library.) + *

+ * WARNING: Do not forget to update ESAPI.properties to change the master key and other security critical settings + * as well as reviewing changes in the esapi-<vers-configuration.jar for differences + * with your current version to see if any important properties were added or removed. + *

* DEPRECATION WARNING: All of the variables of the type '{@code public static final String}' * are now declared and defined in the {@code org.owasp.esapi.PropNames}. These public fields * representing property names and values in this class will be eventually deleted and diff --git a/src/test/java/org/owasp/esapi/ESAPIVerifyAllowedMethods.java b/src/test/java/org/owasp/esapi/ESAPIVerifyAllowedMethods.java new file mode 100644 index 000000000..751a95d52 --- /dev/null +++ b/src/test/java/org/owasp/esapi/ESAPIVerifyAllowedMethods.java @@ -0,0 +1,68 @@ +package org.owasp.esapi; + +import org.bouncycastle.crypto.modes.CBCModeCipher; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.owasp.esapi.errors.ConfigurationException; + + +public class ESAPIVerifyAllowedMethods { + + @Test (expected = IllegalArgumentException.class) + public void verifyNulParamThrows() { + ESAPI.isMethodExplicityEnabled(null); + } + + @Test (expected = IllegalArgumentException.class) + public void verifyEmptyNoWhitespaceParameterThrows() { + ESAPI.isMethodExplicityEnabled(""); + } + + @Test (expected = IllegalArgumentException.class) + public void verifyEmptyOnlyWhitespaceParameterThrows() { + ESAPI.isMethodExplicityEnabled(" "); + } + + @Test (expected = IllegalArgumentException.class) + public void verifyEmptyOnlyTabWhitespaceParameterThrows() { + ESAPI.isMethodExplicityEnabled("\t"); + } + + @Test (expected = IllegalArgumentException.class) + public void verifyEmptyOnlyNewlineWhitespaceParameterThrows() { + ESAPI.isMethodExplicityEnabled("\n"); + } + + + + @Test (expected = IllegalArgumentException.class) + public void verifyNonEsapiPackageParameterThrows() { + ESAPI.isMethodExplicityEnabled("com.myPackage.myScope.method"); + } + @Test + public void verifyUnknownMethodFailsEnableCheck() { + Assert.assertFalse(ESAPI.isMethodExplicityEnabled("org.owasp.esapi.reference.DefaultEncoder.encodeForSQ")); + } + + @Test + public void verifyDefinedRestrictionIsCaught() { + Assert.assertTrue(ESAPI.isMethodExplicityEnabled("org.owasp.esapi.reference.DefaultEncoder.encodeForSQL")); + } + + @Test + public void testMissingPropertyReturnsFalse() { + try { + SecurityConfiguration mockConfig = Mockito.mock(SecurityConfiguration.class); + Mockito.when(mockConfig.getStringProp("ESAPI.dangerouslyAllowUnsafeMethods.methodNames")).thenThrow(ConfigurationException.class); + ESAPI.override(mockConfig); + + Assert.assertFalse(ESAPI.isMethodExplicityEnabled("org.owasp.esapi.thisValueDoesNotMatter")); + Mockito.verify(mockConfig, Mockito.times(1)).getStringProp("ESAPI.dangerouslyAllowUnsafeMethods.methodNames"); + } finally { + ESAPI.override(null); + } + + } + +} diff --git a/src/test/resources/esapi/ESAPI.properties b/src/test/resources/esapi/ESAPI.properties index 7327fbc85..e10691d1f 100644 --- a/src/test/resources/esapi/ESAPI.properties +++ b/src/test/resources/esapi/ESAPI.properties @@ -614,4 +614,4 @@ ESAPI.dangerouslyAllowUnsafeMethods.methodNames=org.owasp.esapi.reference.Defaul # 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 +ESAPI.dangerouslyAllowUnsafeMethods.justification=blah,blah. Please don't fire my @$$. Ticket # 12345-not-the-winning-lotto#