OGNL (Object Graph Navigation Language) is an open source expression engine. Using OGNL, we can use expressions to access arbitrary properties in the Java object tree, call methods in the Java object tree, and so on. That is, if we think of an expression as a string with semantics, OGNL is the catalyst for the communication between this semantic string and Java objects, and OGNL allows us to easily solve various problems encountered in the process of data flow.

/** * from the root object in the given context via the OGNL expression passed in  
public static Object getValue(String expression, Map context, Object root) throws OgnlException {  
  return getValue(expression, context, root, null);  
}  
  
/** * Writes the value */ to the root object in the given context, using the OGNL expression passed in  
public static void setValue(String expression, Map context, Object root, Object value) throws OgnlException {  
  setValue(parseExpression(expression), context, root, value);  
}  
Copy the code

OGNL API is actually quite simple, the above two methods, respectively for the object “value” and “write value” operation. Thus, the basic operation of OGNL is actually implemented by passing in three parameters from these two methods. OGNL also writes many other methods to achieve the same function, and these two interfaces are just the simplest and most representative of them. Readers can read ognl.java for more information.

<! -- https://mvnrepository.com/artifact/ognl/ognl -->
<dependency>
    <groupId>ognl</groupId>
    <artifactId>ognl</artifactId>
    <version>3.2.21</version>
</dependency>
Copy the code
public class Main {

    public static void main(String[] args) throws OgnlException {

        User user = new User();
        user.setId(1);
        user.setName("downpour");

        // Create the context
        Map context = new HashMap();
        context.put("introduction"."My name is ");

        // Tests the expression calculation from the Root object and gets the result
        Object name = Ognl.getValue(Ognl.parseExpression("name"), user);
        System.out.println(name.toString());

        // Test evaluates expressions from context and gets results
        Object contextValue = Ognl.getValue(Ognl.parseExpression("#introduction"), context, user);
        System.out.println(contextValue);
        // The test evaluates both the Root object and the context as part of the expression
        Object hello = Ognl.getValue(Ognl.parseExpression("#introduction + name"), context, user);
        System.out.println(hello);

        // Write to the Root object
        Ognl.setValue("group.name", user, "dev");
        Ognl.setValue("age", user, "18"); System.out.println(user.getGroup().getName()); }}Copy the code

The three elements of OGNL

Expression

Expression is the core of the whole OGNL, all OGNL operations are aimed at the expression after parsing. The expression specifies exactly what the OGNL operation is doing. Thus, an expression is really a string with syntactic meaning that specifies the type and content of the operation.

OGNL supports a wide range of expression syntax, including “chained” descriptions of object access paths, simple calculations in expressions, and even complex Lambda expressions. We can see a variety of different OGNL expressions in the following sections.

Root Object

The Root object of OGNL can be understood as the operation object of OGNL. Once the OGNL expression specifies what to do, we also need to specify who to do it to. The Root object for OGNL is actually a Java object that is the actual carrier for all OGNL operations. This means that if we have an OGNL expression, we actually need to evaluate the OGNL expression against the Root object and return the result.

Context Context

With expressions and Root objects, we can now use the basic functionality of OGNL. For example, an expression can be used to “value” or “write” the Root object in OGNL.

However, in fact, inside OGNL, all operations are run in a specific data environment, which is OGNL’s Context. To be clear, this Context will dictate where OGNL operations are done.

The context of OGNL is a Map structure, called OgnlContext. The Root Object we mentioned earlier will actually be added to the context and will be treated as a special variable.

Basic operations of OGNL

Access to Root objects

Access to the object tree of OGNL’s Root object is achieved by concatenating references to the object using “dots”. In this way, OGNL actually converts a tree object structure into a chained string structure to express semantics.

// Get the value of the name attribute in the Root object
name       
// Get the actual value of the name property in the department property of the Root object
department.name     
// Get the actual value of the name property in the manager property of the department property in the Root object
department.manager.name   
Copy the code

Access to the Context

Since OGNL’s context is a Map structure, it is possible to set some parameters in the context before OGNL performs its calculation and have OGNL carry these parameters into the calculation. Sometimes you need to access parameters in these contexts, which are distinguished from Root objects by a # symbol and a chained expression.

// Get the value of an object named Introduction in the OGNL context
#introduction      
// Get the value of the property named name in the user object named Parameters in the OGNL context
#parameters.user.name  
Copy the code

Access to static variables

In OGNL, static variables or static methods are accessed using @[class]@[field/method] expression syntax.

. / / access com. Example. The core Resource in the class attribute value called the ENABLE
@com.example.core.Resource@ENABLE      
. / / call com. Example. The core Resource class called the get method @ com. Example. Core. The Resource @ the get ()
Copy the code

The method call

Methods can be invoked in OGNL directly through Java-like method invocation, which is done with a dot followed by a method name, and even with passing parameters.

// Call the size() method of users in the group attribute of the Root object
group.users.size()      
// Call containsUser's method in the group of the Root object and pass in the value named requestUser from the context as an argument
group.containsUser(#requestUser) 
Copy the code

[Potential problems arising from OGNL]

* We can already see how powerful OGNL is at the syntactic level. However, the more powerful something is, it must also have its own fatal weakness, which is the so-called “extreme things will reverse”. OGNL’s ability to support a complete Java object creation, reading and writing process makes it a potential entry point for hackers.

Exploit-db reported a Struts2 remote execution of arbitrary code on July 14, 2010. The link to the announcement is www.exploit-db.com/exploits/14…

Careful readers will find that the basic principle of this vulnerability is actually the use of OGNL can arbitrarily construct objects, and execute the characteristics of methods in the object, construct a Java class called by the underlying command, and execute the operating system command for system attack.

In later versions of Struts 2.2.x, this vulnerability was fixed, mainly by limiting parameter names to deny similar code execution. *

Developer.aliyun.com/article/135…