Merge pull request #213 from atlassian-forks/WW-5364-allowlist

WW-5364 Document new OGNL security features
diff --git a/source/plugins/plugins-architecture.md b/source/plugins/plugins-architecture.md
index d43ebbf..9841a65 100644
--- a/source/plugins/plugins-architecture.md
+++ b/source/plugins/plugins-architecture.md
@@ -109,7 +109,9 @@
 | struts.acceptedPatterns.checker         | Used across different interceptors to check if given string matches one of the accepted patterns                                                                                             | request     | com.opensymphony.xwork2.AcceptedPatternsChecker                  |
 | struts.contentTypeMatcher               | Matches content type of uploaded files (since 2.3.22)                                                                                                                                        | singleton   | org.apache.struts2.util.ContentTypeMatcher                       |
 | struts.localizedTextProvider            | Provides access to resource bundles used to localise messages (since 2.5.11)                                                                                                                 | singleton   | com.opensymphony.xwork2.LocalizedTextProvider                    |
-| struts.date.formatter                   | Allow define a date formatter used by `<s:date/>` tag (since 6.0.0)                                                                                                                          | singleton   | org.apache.struts2.components.date.DateFromatter                 |
+| struts.date.formatter                   | Allow define a date formatter used by `<s:date/>` tag (since 6.0.0)                                                                                                                          | singleton   | org.apache.struts2.components.date.DateFormatter                 |
+| struts.ognlGuard                        | Define a custom OgnlGuard implementation to block raw or compiled OGNL expressions (since 6.4.0)                                                                                             | singleton   | org.apache.struts2.ognl.OgnlGuard                                |
+| struts.securityMemberAccess             | Define a custom SecurityMemberAccess implementation, used to restrict OGNL evaluations based on classes involved (since 6.4.0)                                                               | prototype   | com.opensymphony.xwork2.ognl.SecurityMemberAccess                |
 
 ## Plugin Examples
 
diff --git a/source/security/index.md b/source/security/index.md
index af323a1..4cd785f 100644
--- a/source/security/index.md
+++ b/source/security/index.md
@@ -158,7 +158,7 @@
 error pages. This avoids exposing users to XSS attacks as Struts does not escape action's names in automatically 
 generated error pages.
 
-You can eaither disable [DMI](../core-developers/action-configuration#dynamic-method-invocation)
+You can either disable [DMI](../core-developers/action-configuration#dynamic-method-invocation)
 
 ```xml
 <constant name="struts.enable.DynamicMethodInvocation" value="false" />
@@ -176,66 +176,7 @@
 </global-exception-mappings>
 ```
 
-### Proactively protect from OGNL Expression Injections attacks if easily applicable
-
-The framework has a history of critical security bugs, many tied to its use of OGNL technology; Due to its ability to 
-create or change executable code, OGNL is capable of introducing critical security flaws to any framework that uses it. 
-Multiple Struts 2 versions have been vulnerable to OGNL security flaws. Consequently, we've equipped OGNL and the 
-framework with following proactive optional possibilities since OGNL 3.1.24 and Struts 2.5.22. They're disabled by 
-default but via enabling them, you can proactively protect from potential still unknown OGNL Expression Injections flaws:
-
-> **NOTE**: These might break your current app functionality. Before using in production environment, you're recommended
-> to comprehensively test your app UI and functionalities with these enabled.
-
-#### Run OGNL expressions inside sandbox
-
-You can do this simply via adding `-Dognl.security.manager` to JVM arguments. OGNL thereupon utilizes Java Security
-Manager to run OGNL expressions (which includes your actions either!) inside a sandbox with no permission. It is worth 
-noting that it affects only OGNL expression execution and thereafter OGNL reverts Java Security Manager to its previous 
-state.
-
-#### Apply a maximum allowed length on OGNL expressions
-
-You can enable this via Struts configuration key `struts.ognl.expressionMaxLength`. OGNL thereupon doesn't evaluate any 
-expression longer than specified value. You would choose a value large enough to permit ALL valid OGNL expressions used 
-within the application. Values larger than the 200-400 range have diminishing security value (at which point it is 
-really only a "style guard" for long OGNL expressions in an application).
-
-## Internal security mechanism
-
-The Apache Struts 2 contains internal security manager which blocks access to particular classes and Java packages - 
-it's a OGNL-wide mechanism which means it affects any aspect of the framework ie. incoming parameters, expressions 
-used in JSPs, etc. Matching is done based on both the target and member class of an OGNL expression. 
-
-There are 4 options that can be used to configure excluded packages and classes:
-
-- `struts.excludedClasses`: comma-separated list of excluded classes. Note that superclasses are also matched.
-- `struts.excludedPackageNames`: comma-separated list of excluded packages, matched using string
-  comparison via `startWith`. Note that classes in subpackages are also excluded.
-- `struts.excludedPackageNamePatterns` - comma-separated list of RegEx patterns used to exclude packages. Note that this
-  option is slower than string comparison but more flexible.
-- `struts.excludedPackageExemptClasses` - comma-separated list of classes to exempt from any of the excluded packages or
-  package name patterns. An exact exemption must exist for each exclusion match (target or member or both).
-
-The defaults are defined [here](https://github.com/apache/struts/blob/master/core/src/main/resources/struts-excluded-classes.xml).
-
-Any expression or target which evaluates to one of these will be blocked and you see a WARN in logs:
-
-```
-[WARNING] Target class [class example.MyBean] or declaring class of member type [public example.MyBean()] are excluded!
-```
-
-In that case `new MyBean()` was used to create a new instance of class (inside JSP) - it's blocked because `target` 
-of such expression is evaluated to `java.lang.Class`
-
-It is possible to redefine the above constants in struts.xml but try to avoid this and rather change design of your application!
-
-### Accessing static methods
-
-Support for accessing static methods from expression will be disabled soon, please consider re-factoring your application 
-to avoid further problems! Please check [WW-4348](https://issues.apache.org/jira/browse/WW-4348).
-
-### OGNL is used to call action's methods
+### Ambiguous Action Methods
 
 This can impact actions which have large inheritance hierarchy and use the same method's name throughout the hierarchy, 
 this was reported as an issue [WW-4405](https://issues.apache.org/jira/browse/WW-4405). See the example below:
@@ -267,12 +208,12 @@
 To solve the problem don't use the same method's names through the hierarchy, you can simply change the action's method 
 from `save()` to `saveAction()` and leaving annotation as is to allow call this action via  `/save.action` request.
 
-### Accepted / Excluded patterns
+### Accepted / Excluded Patterns
 
 As from version 2.3.20 the framework provides two new interfaces which are used to accept / exclude param names 
 and values - [AcceptedPatternsChecker](../maven/struts2-core/apidocs/com/opensymphony/xwork2/security/AcceptedPatternsChecker) 
 and [ExcludedPatternsChecker](../maven/struts2-core/apidocs/com/opensymphony/xwork2/security/ExcludedPatternsChecker) 
-with default implementations. These two interfaces are used by [Parameters Interceptor](../core-developers/parameters-interceptor) 
+with default implementations. These two interfaces are used by the [Parameters Interceptor](../core-developers/parameters-interceptor) 
 and [Cookie Interceptor](../core-developers/cookie-interceptor) to check if param can be accepted or must be excluded. 
 If you were using `excludeParams` previously please compare patterns used by you with these provided by the framework in default implementation.
 
@@ -286,7 +227,7 @@
 
 > Note: since Struts 6.0.0
 
-Fetch Metadata is a mitigation against common cross origin attacks such as Cross-Site Request Forgery (CSRF). It is 
+Fetch Metadata is a mitigation against common cross-origin attacks such as Cross-Site Request Forgery (CSRF). It is 
 a web platform security feature designed to help servers defend themselves against cross-origin attacks based 
 on the preferred resource isolation policy. The browser provides information about the context of an HTTP request 
 in a set of `Sec-Fetch-*` headers. This allows the server processing the request to make decisions on whether the request 
@@ -328,3 +269,143 @@
 
 COOP and COEP are implemented in Struts using [CoopInterceptor](../core-developers/coop-interceptor) 
 and [CoepInterceptor](../core-developers/coep-interceptor).
+
+## Proactively protecting against OGNL Expression Injections attacks
+
+The framework has a history of critical security bugs, many tied to its use of OGNL technology; Due to its ability to
+create or change executable code, OGNL is capable of introducing critical security flaws to any framework that uses it.
+Multiple Struts 2 versions have been vulnerable to OGNL security flaws. Consequently, we've equipped OGNL and the
+framework with a number of additional security capabilities, some of which need to be manually enabled.
+
+> **NOTE**: These might break your current app functionality. Before using in production environment, you're recommended
+> to comprehensively test your app UI and functionalities with these enabled.
+
+### Run OGNL expressions inside sandbox
+
+You can do this simply via adding `-Dognl.security.manager` to JVM arguments. OGNL thereupon utilizes Java Security
+Manager to run OGNL expressions (which includes your actions either!) inside a sandbox with no permission. It is worth
+noting that it affects only OGNL expression execution and thereafter OGNL reverts Java Security Manager to its previous
+state.
+
+Note: This feature does not work with JDK 21 and above.
+
+### Apply a maximum allowed length on OGNL expressions
+
+You can enable this via Struts configuration key `struts.ognl.expressionMaxLength` (defaults to 256). OGNL thereupon doesn't evaluate any
+expression longer than specified value. You would choose a value large enough to permit ALL valid OGNL expressions used
+within the application. Values larger than the 200-400 range have diminishing security value (at which point it is
+really only a "style guard" for long OGNL expressions in an application).
+
+### OGNL Member Access
+
+Struts 2 implements an OGNL internal security mechanism which blocks access to particular classes and Java packages -
+it's an OGNL-wide mechanism which means it affects any aspect of the framework i.e. incoming parameters, expressions
+used in JSPs, etc. Matching is done based on both the target and member class of all components of an OGNL expression.
+
+There are 4 options that can be used to configure excluded packages and classes:
+
+- `struts.excludedClasses`: comma-separated list of excluded classes.
+- `struts.excludedPackageNames`: comma-separated list of excluded packages, matched using string comparison via
+  `startWith`. Note that classes in subpackages are also excluded.
+- `struts.excludedPackageNamePatterns` - comma-separated list of RegEx patterns used to exclude packages. Note that this
+  option is more flexible than `struts.excludedPackageNames` but will have a greater impact on performance and page 
+  latency.
+- `struts.excludedPackageExemptClasses` - comma-separated list of classes to exempt from any of the excluded packages or
+  package name patterns. An exact exemption must exist for each exclusion match (target or member or both).
+
+The defaults are defined [here](https://github.com/apache/struts/blob/master/core/src/main/resources/struts-excluded-classes.xml).
+
+Additionally, static methods are blocked, and static fields can also be blocked with 'struts.allowStaticFieldAccess'.
+
+Any expression or target which does not pass this criteria will be blocked, and you will see a warning in the logs:
+
+```
+[WARNING] Target class [class example.MyBean] or declaring class of member type [public example.MyBean()] are excluded!
+```
+
+In that case `new MyBean()` was used to create a new instance of class (inside JSP) - it's blocked because the `target`
+of such expression is `java.lang.Class` which is excluded.
+
+It is possible to redefine the above constants in `struts.xml`, but avoid reducing the list, instead extending the list
+with other known dangerous classes or packages in your application.
+
+#### Allowlist Capability
+
+> Note: since Struts 6.4.
+
+For even more stringent OGNL protection, we recommend enabling the allowlist capability with `struts.allowlist.enable`.
+
+Now, in addition to enforcing the exclusion list, classes involved in OGNL expression must also belong to a list of
+allowlisted classes and packages. By default, all required Struts classes are allowlisted as well as any classes that
+are defined in your `struts.xml` package configurations.
+
+You can add additional classes and packages to the allowlist with:
+
+- `struts.allowlist.classes`: comma-separated list of allowlisted classes.
+- `struts.allowlist.packages`: comma-separated list of allowlisted packages, matched using string comparison via
+  `startWith`. Note that classes in subpackages are also allowlisted.
+
+Generally, the only additional classes or packages you will need to configure are those model classes that you wish to
+be constructed/manipulated by Struts form submissions (i.e. parameter injected).
+
+#### Extensibility
+
+> Note: since Struts 6.4.
+
+The OGNL Member Access mechanism is extensible, allowing you to define your own rules for blocking access to OGNL
+expression evaluations. To do so, you may use the `struts.securityMemberAccess` extension point. Please be vigilant when
+overriding methods as not to reduce protections offered by the default implementation.
+
+### Struts OGNL Guard
+
+> Note: since Struts 6.4.
+
+The Struts OGNL Guard allows applications to completely disable certain OGNL expression features/capabilities. This
+feature is disabled by default but can be enabled and configured with `struts.ognl.excludedNodeTypes`.
+
+It is recommended to disable any OGNL feature you are not leveraging in your application. For applications using a
+minimal number of Struts features, you may find the following list a good starting point.
+
+Please be aware that this list WILL break certain Struts features:
+
+```xml
+<constant name="struts.ognl.excludedNodeTypes"
+          value="
+            ognl.ASTAdd,
+            ognl.ASTAssign,
+            ognl.ASTBitAnd,
+            ognl.ASTBitNegate,
+            ognl.ASTBitOr,
+            ognl.ASTCtor,
+            ognl.ASTDivide,
+            ognl.ASTEval,
+            ognl.ASTIn,
+            ognl.ASTInstanceof,
+            ognl.ASTKeyValue,
+            ognl.ASTList,
+            ognl.ASTMap,
+            ognl.ASTMultiply,
+            ognl.ASTNegate,
+            ognl.ASTNotIn,
+            ognl.ASTProject,
+            ognl.ASTRootVarRef,
+            ognl.ASTSelect,
+            ognl.ASTSelectFirst,
+            ognl.ASTSelectLast,
+            ognl.ASTSequence,
+            ognl.ASTShiftLeft,
+            ognl.ASTShiftRight,
+            ognl.ASTStaticField,
+            ognl.ASTStaticMethod,
+            ognl.ASTThisVarRef,
+            ognl.ASTUnsignedShiftRight,
+            ognl.ASTVarRef,
+            ognl.ASTXor
+"/>
+```
+
+#### Extensibility
+
+The Struts OGNL Guard mechanism is extensible, allowing you to define your own rules for blocking access to both raw
+OGNL expressions and compiled syntax trees. To do so, you may use the `struts.ognlGuard` extension point. You may choose
+to override the default implementation or implement the `OgnlGuard` interface directly.