【问题标题】:Does the ModelDriven interface poses a security explot in struts2?模型驱动接口是否会在 struts2 中构成安全漏洞?
【发布时间】:2010-07-26 18:47:17
【问题描述】:

背景:我用 ModelDriven 编写了一个 struts2 ActionSupport 类。这是一个 hibernate/spring web 应用程序,使用 OSIV 和视图中的附加实体 (JSP)。

我今天收到了建筑师“惩罚”我放置物品的这封电子邮件 通过 ModelDriven<E> 接口。他是对的还是什么?显然,这是我正在做的一件严肃的事情,但我并没有听从他的话,而且我真的不想接受他的提议并在那之后去他的办公桌前拜访他。好家伙。是时候换个职业了。

---来自建筑师---

Billy,正如我们之前所讨论的,您的代码中仍然存在同样的错误 一遍又一遍地。这是您第四次犯此错误,我很担心 关于你的工作质量。做一次甚至两次是一回事,但是 第四次之后,我想知道你是否无法理解我在说什么。下面将为您一一解读。如果您在阅读此电子邮件后没有收到它,请到我的办公桌前,我们会仔细阅读。这必须立即停止,我想要所有 你的代码在一天结束之前重构,纠正了这个错误。如果有任何代码喜欢 这会流血到生产中,我们将面临严重的安全问题。另请注意,我在这方面抄袭戴夫,以便发出适当的谴责。我还将向 Dave 推荐您从 III 级开发人员转到 II 级开发人员。请阅读以下内容并学习它,并按照我的指示重构您的所有代码。

关于绑定对象:

当一个 Struts2 动作类被标记为 ModelDriven 接口时,模型 将绑定到 HTML 页面中的表单元素。例如,如果一个 HTML 表单 有一个名为 userName 的字段和一个动作类定义为:

公共类 UserAction 扩展 ActionSupport 实现 ModelDriven

而UserModel是一个POJO如下:

public class UserModel {
  private String userName;

  public String getUserName() {
      return userName;
  }

  public void setUserName(String userName) { 
      this.userName = userName;
  }
}

表单提交时,只要Action包含UserModel的实例,struts2 将字段 userName 绑定到 UserModel.userName,自动填充值。

但是,这种简单性对于恶意用户来说代价高昂。如果声明了一个对象 作为 ModelDriven,最终用户,即浏览用户,可以访问模型图 通过模型设置器。以这个案例为例:

公共类 UserAction 扩展 ActionSupport 实现 ModelDriven

还有……

public class UserModel {
  private String userName;
  private UserEntity userEntity;

  public String getUserName() {
      return userName;
  }

  public void setUserName(String userName) { 
      this.userName = userName;
  }

  pubic UserEntity getUserEntity() {
      return userEntity;
  }
}

还有……

@Entity
public class UserEntity {
    private String password;

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
 }

假设正在使用 OSIV 模式,并且附加了实体 UserEntity。

有一点先见之明或手头有时间的狡猾用户可能会:

/myform?userName=billy&userEntity.password=newpassword

假设实体在会话结束时保存,上述结果会发生变化 比利的密码。

关键是,对象图是可用的!

当使用 ModelDriven 并且使用替代方法是一种可怕的方法时,您必须定义 放置在 valuestack 上的细粒度模型,然后从模型复制到 在发送响应并允许事务提交之前的目标对象。

【问题讨论】:

    标签: java hibernate struts2 exploit


    【解决方案1】:

    您的架构师是对的,将有权访问敏感信息的对象放在 ValueStack 上会带来潜在的安全风险。恶意用户确实可以通过上述攻击重置密码。

    但是:

    由于他是一名架构师,他应该设计出正确验证/限制输入参数的方法。在 Struts2 中使用 ParamsInterceptor 很容易只允许将特定参数传递给动作。因此,糟糕的不是你的工作,而是你的系统架构。 开发人员应该能够专注于实现业务逻辑。基础架构必须由架构师提供。

    干杯,

    w

    【讨论】:

      【解决方案2】:

      ModelDriven 拦截器是盲目的

      是的,模型接口可能是安全问题的根源,如果您不处理传入参数,您将面临安全漏洞。

      你必须使用参数拦截器。

      在 struts.xml 中将你的 params 拦截器更改为:

      <interceptor-ref name="params">
          <param name="excludeParams">\w+((\.\w+)|(\[\d+\])|(\(\d+\))|(\['\w+'\])|(\('\w+'\)))*</param>
      </interceptor-ref>
      

      然后在您的操作中实现ParameterNameAware 并写入acceptableParameterName

      public class sample implements ParameterNameAware(){
              public boolean acceptableParameterName(String parameterName) {  
             if (("username".equals(parameterName) || 
                  "firstname".equals(parameterName) ||
                  "lastname".equals(parameterName))
                  return true;
              else
                 return false;
          }
      
      }  
      

      以上内容很重要,如果您的用户 pojo 有很多其他属性并且只有其中一些应该从用户那里获取。

      如果您使用大量 ModelDriven 操作,您可以使其通用。

      创建一个扩展 ParameterNameAware 的基本操作。然后尝试开发一种通用方法来列出您的操作和有效参数:

      我们使用 spring 来读取动作列表及其可接受的参数。在我们添加的spring xml中:

      <util:properties id="actionsValidParameters"
          location="classpath:/configs/actions-valid-parameters.properties" />
      

      actions-valid-parameters.properties 如下:

      save-user=username,description,firstname,lastname
      save-address=zipcode,city,detail,detail.addLine1,detail.addLine2,detail.no
      

      提示,如果地址对象有一个 Detail 对象,并且您想在 Detail 对象中填充一些属性,请确保在上面的列表中包含“detail”。

      动作如下

      public class BaseActionSupport extends ActionSupport implements ParameterNameAware
      {
      
      @Resource(name = "actionsValidParameters")
      public Properties actionsValidParameters;
      
      @Override
      public boolean acceptableParameterName(String parameterName) {
      
          String actionName = ActionContext.getContext().getName();
           String validParams = (String) actionsValidParameters.get(actionName);
      
          //If the action is not defined in the list, it is assumed that the action  can accept all parameters. You can return false so if the action is not in the list no parameter is accepeted. It is up to you!
          if(StringUtils.isBlank(validParams))
              return true;
          // Search all the list of parameters. 
                  //You can split the validParams to array and search array.  
          Pattern pattern = Pattern.compile("(?<=^|,)" + parameterName
                  + "(?=,|$)");
          Matcher matcher = pattern.matcher(validParams);
          boolean accepeted = matcher.find();
          LOG.debug(
                  "The {} parameter is {} in action {}, Position (excluding the action name) {} , {} , mathced {} ",
                  parameterName, accepeted, actionName, matcher.start(), matcher.end(),
                  matcher.group());
          return accepeted;
          }
      
      }
      

      现在把你的动作写成

        public class UserAction extends BaseActionSupport implements  
              ModelDriven<User>{
      
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-17
        • 2017-11-24
        相关资源
        最近更新 更多