0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Strutsの「Auto growth collection limit(Collectionの要素数が256を超えるとエラーになる)の回避方法

Posted at

問題の事象

StrutsではDOS攻撃対策として要素数が256件を超えるCollection型の項目をPOSTするとエラーが発生する。

HelloAction.java
public class HelloAction extends ActionSupport {
    private List<String> addresses;

    public List<String> getAddresses() {
        return this.addresses;
    }

    public setAddresses(List<String> addresses) {
        this.addresses = addresses;
    }

    public String execute() {
        if (this.addresses.isEmpty()) {
            for (int i = 0; i < 300; i++) {
                this.addresses.add("Address" + i);
            }
        }
        return SUCCESS;
    }
}
hello.jsp(抜粋)
<s:form action="hello" method="post">
    Address:<br/>
    <s:iterator value="addresses" status="status">
        <s:textfield name="addresses[%{#status.count - 1}]"/><br/>
    </s:iterator>
    <s:submit type="input" />
</s:form>

image.png

submitすると256個以降がエラーになる
image.png
このチェックはcom.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessorクラスで行われている。

XWorkListPropertyAccessor.java(抜粋)
if (target instanceof List && name instanceof Number) {
   List list = (List)target;
   int listSize = list.size();
   count = ((Number)name).intValue();
   if (count > this.autoGrowCollectionLimit) {
      throw new OgnlException("Error auto growing collection size to " + count + " which limited to " + this.autoGrowCollectionLimit);
   }

   if (count >= listSize) {
      for(i = listSize; i <= count; ++i) {
         list.add((Object)null);
      }
   }
}

対策

考えられる対策方法を以下に記す

  • 定数struts.ognl.autoGrowthCollectionLimitを変更する
  • Type Conversionを使う
  • Mapに変更する
  • XWorkListPropertyAccessorの代わりにListPropertyAccessorを使用する

定数struts.ognl.autoGrowthCollectionLimitを変更する

公式HPに記載されているとおりCollectionの自動拡張の上限を変更する。一番簡単な方法と思うが、Listを使っている箇所すべてで制限が緩くなるのが欠点だと思う。

struts.xml
<constant name="struts.ognl.autoGrowthCollectionLimit" value="1024"/>

Type Conversionを使う

Type Conversionを使えば特定の項目のみに限定して制限をなくすことができる。XWorkListPropertyAccessorクラスはType Conversionを使用した場合には上限を適用しないことを利用する。
List<String>のように要素が書き込み不可の場合は適用できない。

Address.java
// Listに格納するJavaBean
public class Address {
	private String id;
	private String address;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}
}
HelloAction.java
package org.demo;

public class HelloAction extends ActionSupport {
    private List<Address> addresses;

    public List<Address> getAddresses() {
        return this.addresses;
    }

    public setAddresses(List<Address> addresses) {
        this.addresses = addresses;
    }

    public String execute() {
        // 初期表示時に要素を300個にする
        if (this.addresses.isEmpty()) {
            for (int i = 0; i < 300; i++) {
                Address address = new Address();
                address.setId("id" + i);    // jspで丸括弧を使う書き方をする場合は必要
                this.addresses.add(address);
            }
        }
        return SUCCESS;
    }
}
hello.jsp(抜粋)
<s:form action="hello" method="post">
    Address:<br/>
    <s:iterator value="addresses" status="status">
        <s:textfield name="addresses[%{#status.count - 1}].address"/><br/>
        <!-- ↓丸括弧を使う書き方も可能 -->
        <!-- <s:textfield name="addresses(%{'\\'id' + (#status.count - 1) + '\\''}).address"/><br/> -->
    </s:iterator>
    <s:submit type="input" />
</s:form>

以下はHelloAction.javaと同じフォルダに置くか、src/main/resources配下にHelloActionと同じパッケージ階層のフォルダを作成して配置する。

HelloAction-conversion.properties
KeyProperty_addresses=x  ←デタラメでよい。丸括弧を使う書き方の場合はidのようなキーにする項目を指定する
Element_addresses=org.demo.Address
CreateIfNull_addresses=true

以下のような画面となり、submitしてもエラーはならない。
image.png

Mapに変更する

Collectionと違ってMapには上限が適用されないためMapにすることで解決する。
Stringでも使用できる。

HelloAction.java
package org.demo;

public class HelloAction extends ActionSupport {
    private Map<Integer, String> addresses;

    public Map<Integer, String> getAddresses() {
        return this.addresses;
    }

    public setAddresses(Map<Integer, String> addresses) {
        this.addresses = addresses;
    }

    public String execute() {
        // 初期表示時に要素を300個にする
        if (this.addresses.isEmpty()) {
            for (int i = 0; i < 300; i++) {
                this.addresses.put(i, "");
            }
        }
        return SUCCESS;
    }
}
hello.jsp(抜粋)
<s:form action="hello" method="post">
    Address:<br/>
    <s:iterator value="addresses" status="status">
        <s:textfield name="addresses[%{#status.count - 1}]"/><br/>
    </s:iterator>
    <s:submit type="input" />
</s:form>

XWorkListPropertyAccessorの代わりにListPropertyAccessorを使用する

大げさかもしれないがOGNLが使用するAccessorを変更することで上限を適用しないようにする。
ArrayListを継承したカスタムリストを作成

MyList.java
package org.demo;

import java.util.ArrayList;

public class MyList<T> extends ArrayList<T> {
}

カスタムリストに対しては上限チェックを行わないAccessorを使用する

struts.xml(抜粋)
<bean type="ognl.PropertyAccessor" name="org.demo.converter.MyList"
          class="ognl.ListPropertyAccessor"/>
HelloAction.java
package org.demo;

public class HelloAction extends ActionSupport {
    private MyList<String> addresses = new MyList<>();

    public MyList<String> getAddresses() {
        return this.addresses;
    }

    public void setAddresses(MyList<String> addresses) {
        this.addresses = addresses;
    }

    public HelloAction() {
        // 自動的にリストを拡張してくれないのでコンストラクタで300個にする
        for (int i = 0; i < 300; i++) {
            this.addresses.add("");
        }
    }

    public String execute() {
        return SUCCESS;
    }
}
hello.jsp(抜粋)
<s:form action="hello" method="post">
    Address:<br/>
    <s:iterator value="addresses" status="status">
        <s:textfield name="addresses[%{#status.count - 1}]"/><br/>
    </s:iterator>
    <s:submit type="input" />
</s:form>

リストを自動的に拡張してくれないのがいまいちだ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?