2

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

我今天从架构师那里收到了这封电子邮件,因为我通过接口将一个引用了附加实体的对象放在了 struts2 值堆栈上 ModelDriven<E>。他是对的还是什么?显然,这是我正在做的一件严肃的事情,但我并没有听从他的话,而且我真的不想接受他的提议并在那之后去他的办公桌前拜访他。好家伙。是时候换职业了。

---来自建筑师---

比利,正如我们之前所讨论的,你仍然在你的代码中一遍又一遍地犯同样的错误。这是您第四次犯此错误,我担心您的工作质量。做一次甚至两次是一回事,但第四次之后,我想知道你是否无法理解我在说什么。下面将为您一一解读。如果您在阅读此电子邮件后没有收到它,请到我的办公桌前,我们会仔细阅读。这必须立即停止,我希望在一天结束之前重构您的所有代码以纠正这个错误。如果任何这样的代码渗入生产环境,我们将面临严重的安全问题。另请注意,我在这方面抄袭戴夫,以便发出适当的谴责。我还将向 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 上的细粒度模型,然后在发送响应并允许事务提交之前从模型复制到目标对象。

4

2 回答 2

1

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

但:

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

干杯,

w

于 2010-11-08T18:35:55.900 回答
0

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 对象中填充一些属性,请确保在上面的列表中包含“详细信息”。

动作如下

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>{


}
于 2013-12-11T21:15:51.327 回答