|
16 | 16 | */ |
17 | 17 | package org.owasp.esapi; |
18 | 18 |
|
| 19 | +import java.util.Arrays; |
| 20 | + |
19 | 21 | import javax.servlet.http.HttpServletRequest; |
20 | 22 | import javax.servlet.http.HttpServletResponse; |
21 | 23 |
|
22 | 24 | import org.owasp.esapi.util.ObjFactory; |
| 25 | +import org.owasp.esapi.errors.ConfigurationException; |
23 | 26 |
|
24 | 27 | /** |
25 | 28 | * 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() { |
93 | 96 | } |
94 | 97 |
|
95 | 98 | /** |
96 | | - * The ESAPI Encoder is primarily used to provide <i>output</i> encoding to |
| 99 | + * The ESAPI {@code Encoder} is primarily used to provide <i>output</i> encoding to |
97 | 100 | * prevent Cross-Site Scripting (XSS). |
98 | | - * @return the current ESAPI Encoder object being used to encode and decode data for this application. |
| 101 | + * @return the current ESAPI {@code Encoder} object being used to encode and decode data for this application. |
99 | 102 | */ |
100 | 103 | public static Encoder encoder() { |
101 | 104 | return ObjFactory.make( securityConfiguration().getEncoderImplementation(), "Encoder" ); |
102 | 105 | } |
103 | 106 |
|
104 | 107 | /** |
105 | | - * @return the current ESAPI Encryptor object being used to encrypt and decrypt data for this application. |
| 108 | + * ESAPI {@code Encryptor} provides a set of methods for performing common encryption, random number, and |
| 109 | + * hashing operations. |
| 110 | + * @return the current ESAPI {@code Encryptor} object being used to encrypt and decrypt data for this application. |
106 | 111 | */ |
107 | 112 | public static Encryptor encryptor() { |
108 | 113 | return ObjFactory.make( securityConfiguration().getEncryptionImplementation(), "Encryptor" ); |
@@ -221,4 +226,74 @@ public static String initialize( String impl ) { |
221 | 226 | public static void override( SecurityConfiguration config ) { |
222 | 227 | overrideConfig = config; |
223 | 228 | } |
| 229 | + |
| 230 | + // KWW - OPEN ISSUE: I don't like placing this here, but it's convenient and I |
| 231 | + // don't really know a better place for it and would rather not create |
| 232 | + // a whole new utility class just to use it. |
| 233 | + /** |
| 234 | + * Determine if a given fully qualified (ESAPI) method name has been explicitly |
| 235 | + * enabled in the <b>ESAPI.properties</b>'s file via the property name |
| 236 | + * <b>ESAPI.dangerouslyAllowUnsafeMethods.methodNames</b>. Note that there |
| 237 | + * is no real reason for an ESAPI client to use this, It is intended for |
| 238 | + * interal use, |
| 239 | + * </p><p> |
| 240 | + * The reason this method exists is because certain (other) ESAPI method names |
| 241 | + * are considered "unsafe" and therefore should be used with extra caution. |
| 242 | + * These "unsafe" methods may include methods that are: |
| 243 | + * <ul> |
| 244 | + * <li>Deprecated and thus no longer suggested for long term use.</li> |
| 245 | + * <li>Methods where the programming contract is not in itself sufficient to ensure safety alone |
| 246 | + * and developers are expected to take addional actions on their own to secure their application.</li> |
| 247 | + * <li>Methods that are using some unpatched transitive dependency that we haven't firmly |
| 248 | + * established grounds for it not being exploitable in the manner that ESAPI uses it.</li> |
| 249 | + * <li>Methods whose reference implementations are not scalable to the enterprise level.</li> |
| 250 | + * </ul> |
| 251 | + * <i>Public</i> methods that are not in that list for the above ESAPI property |
| 252 | + * are generally are considered enabled and okay to use unless their Javadoc |
| 253 | + * indicates otherwise. |
| 254 | + * </p><p> |
| 255 | + * Note that this method is intended primarilly for internal ESAPI use and if we were |
| 256 | + * using Java Modules (in JDK 9 and later), this method would not be exported. |
| 257 | + * </p><p> |
| 258 | + * For further details, please see the ESAPI GitHub wiki article, |
| 259 | + * <a href="https://github.com/ESAPI/esapi-java-legacy/wiki/Reducing-the-ESAPI-Library's-Attack-Surface">"Reducing the ESAPI Library's Attack Surface"</a>. |
| 260 | + * @param fullyQualifiedMethodName A fully qualified ESAPI class name (so, should start |
| 261 | + * "org.owasp.esapi.") followed by the method name (but without |
| 262 | + * parenthesis or any parameter signature information. |
| 263 | + * @return {@code true} if the parameter {@code fullyQualifiedMethodName} is in the comma-separated |
| 264 | + * list of values in the ESAPI property <b>ESAPI.dangerouslyAllowUnsafeMethods.methodNames</b>, |
| 265 | + * otherwise {@code false} is returned. |
| 266 | + */ |
| 267 | + public static boolean isMethodExplicityEnabled(String fullyQualifiedMethodName) { |
| 268 | + if ( fullyQualifiedMethodName == null || fullyQualifiedMethodName.trim().isEmpty() ) { |
| 269 | + throw new IllegalArgumentException("Program error: fullyQualifiedMethodName parameter cannot be null or empty"); |
| 270 | + } |
| 271 | + String desiredMethodName = fullyQualifiedMethodName.trim(); |
| 272 | + // This regex is too liberal to be anything more than just a trivial |
| 273 | + // sanity test to protect against typos. |
| 274 | + if ( !desiredMethodName.matches("^org\\.owasp\\.esapi\\.(\\p{Alnum}|\\.)*$") ) { |
| 275 | + throw new IllegalArgumentException("Program error: fullyQualifiedMethodName must start with " + |
| 276 | + "'org.owasp.esapi.' and be a valid method name."); |
| 277 | + } |
| 278 | + |
| 279 | + String enabledMethods = null; |
| 280 | + try { |
| 281 | + // Need to do this w/in a try/catch because if the property is not |
| 282 | + // found, getStringProp will throw a ConfigurationException rather |
| 283 | + // than returning a null. |
| 284 | + enabledMethods = securityConfiguration().getStringProp("ESAPI.dangerouslyAllowUnsafeMethods.methodNames"); |
| 285 | + } catch( ConfigurationException cex ) { |
| 286 | + return false; // Property not found at all. |
| 287 | + } |
| 288 | + |
| 289 | + |
| 290 | + // Split it up by ',' and then filter it by finding the first on that |
| 291 | + // matches the desired method name passed in as the method parameter. |
| 292 | + // If no matches, return the empty string. |
| 293 | + String result = Arrays.stream( enabledMethods.trim().split(",") ) |
| 294 | + .filter(methodName -> methodName.trim().equals( desiredMethodName ) ) |
| 295 | + .findFirst() |
| 296 | + .orElse(""); |
| 297 | + return !result.isEmpty(); |
| 298 | + } |
224 | 299 | } |
0 commit comments