Struts 2 Security Vulnerability - Dynamic Method Invocation

Introduction

The Struts 2 web application framework has a long-standing security vulnerability that may not be well known to new Struts 2 developers. By default the framework enables a technique called dynamic method invocation. This technique allows a developer to specify in a Struts 2 action url what method should be called in the Action class. The security problem is that any user of the Struts 2 web application can also use dynamic method invocation to call a public method that is in the Action class. The purpose of this article is to explain the vulnerability and how to fix it. Note this problem occurs through the Struts 2.2.1.1 release, which is the latest release as of February 2011.

Please note that this security issue is well-known to most experienced Struts 2 developers and to the Struts 2 framework committers. They are working on a permanent fix in a future Struts 2 release. You can learn more about this vulnerability and its fix by searching the Struts 2 developers mailing list. My goal with this article is to better inform new Struts 2 developers about this vulnerability and how to prevent it.

NOTE: With the release of Struts 2.3.1.1 in December 2011, the security issue with using dynamic method invocation was addressed.  However, by default even in version 2.3.1.1, the vulnerability exists and developers must add additional markup to their package statement to prevent users being able to execute public methods.  See http://struts.apache.org/2.3.1/docs/action-configuration.html#ActionConfiguration-DynamicMethodInvocation for more detail.

Dynamic Method Invocation

In Struts 2, you can use the bang (!) operator to specify which method should be executed in the Action class. For example, let's say I have an action named recoverpassword that is mapped to class RecoverPassword. In class RecoverPassword is public method getUserPassword. I can use the bang operator to tell the Struts 2 framework to execute method getUserPassword when action recoverpassword is specified in the URL. I can do this by constructing the URL as follows:

http://localhost:8080/mywebapp/recoverpassword!getUserPassword.action

The part after the bang operator is the method Struts 2 should execute in the class associated with the recoverpassword action.

Note that method getUserPassword must be public and have no parameters. In Struts 2, by default, dynamic method invocation is allowed. Any user of the web application can play around with calling your application's URLs trying to get Struts 2 to execute a method.

For more information about  dynamic method invocation see: http://struts.apache.org/2.2.1.1/docs/action-configuration.html#ActionConfiguration-DynamicMethodInvocation.

Example Application

To help illustrate the vulnerability, I've created a simple example application which you can download or view here:

http://www.bpjava.net/struts2_security_vulnerability/

You can download the example project, named Struts2_Security_Vulnerability_Example. The project was created using Eclipse 3.6 and Maven. It is a standard Maven project so if you don't have Eclipse, you should be able to import the unzipped project into any Java IDE that supports Maven.

To build the application's war file run mvn clean package from the project's root folder. The war file is created in the target sub-folder. Copy the war file to your Servlet container (e.g. Tomcat, GlassFish) and  then startup the Servlet container.

In a web browser go to: 

http://localhost:8080/struts2_security_vulnerability/index.action
(note for this URL and the others that follow if you want to use the example application I deployed to my own server, replace localhost:8080 in the URL with www.bpjava.net - for example http://www.bpjava.net/struts2_security_vulnerability/index.action).

You should see a web page with Welcome to Struts 2!

Security Vulnerability Caused By Dynamic Method Invocation

  The Action class RecoverPassword has a public method called getPassword and the project has not disabled dynamic method invocation. So a user entering this URL  in the browser:

http://localhost:8080/struts2_security_vulnerability/recoverpassword!getPassword.action

will see the String returned by the method getPassword.  Note that recoverpassword must be matched to an Action class that has a public getPassword method that has no parameters.

The result of the url:

http://localhost:8080/struts2_security_vulnerability/recoverpassword!getPassword.action

will either be a 404 error or a stack trace if the struts devmode property is true. The 404 error page will include this line:

No result defined for action edu.ku.it.si.struts2securityvulnerability.security.action.RecoverPassword  and result user_secrect_password

The last part above is the String returned by method getPassword, which in this  example is the user's password. The stack trace will include a similar line that exposes the user's password.

Any public method in the Action class that has no parameters is vulnerable, even  if the method returns no value.  For example enter this URL in the example application:

http://localhost:8080/struts2_security_vulnerability/changepassword!changePassword.action?newPassword=my_new_password&username=bruce

You will not see anything in the browser after the URL executes, but the above URL will cause method changePassword to be executed (see class ChangePassword ) and the password for user bruce will be changed to my_new_password.  This URL completely bypasses the authentication check in the execute method of  class ChangePassword. (To verify that method changePassword was called see the console output after executing the above URL.)

How To Fix The Dynamic Method Invocation Security Vulnerability

Include in struts.xml this Struts 2 property setting:

<constant name="struts.enable.DynamicMethodInvocation" value="false" />

or in struts.properties:

struts.enable.DynamicMethodInvocation = false

or in web.xml include this init-param node in the Struts 2 filter:



<init-param>
<param-name>struts.enable.DynamicMethodInvocation</param-name>
<param-value>false</param-value>
</init-param>

In the example application's struts.xml uncomment that property setting to fix the problem in the example.

The above setting will prevent Struts 2 from parsing the bang operator (!) in the URL, so then the whole part before .action will be used to match to a configured Struts 2 action. 

For example with this URL

http://localhost:8080/struts2_security_vulnerability/recoverpassword!getPassword.action

instead of method getPassword being called on the Action class matched to action recoverpassword, the  Struts 2 framework will try to find an action named "recoverpassword!getPassword" (which won't exist).

Other Good Practices To Follow When Designing Struts 2 Action classes

1.  The only methods in the Action class that should be public are the those methods specifically matched to a Struts 2 action (e.g. execute, input) and get/set methods for the instance fields  that are exposed to the view pages.

2.  All methods that do some work on behalf of the action should be in a Service layer class and not in the  ActionSupport class.

Summary

Hopefully this article will convince Struts 2 developers to always include setting the DynamicMethodInvocation property to false to prevent the use of the bang operator to call specific methods in the Action class.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值