Struts1の脆弱性問題で、commons-beanutilsに対応が入ったバージョン1.9.2がリリースされました。
https://issues.apache.org/jira/browse/BEANUTILS-463
といっても、デフォルトで問題が修正されるわけではなく、セットアップは必要です。
仕組み
BeanIntrospectorという仕組みが1.9.xからは導入されていて、PropertyUtilsにこのBeanIntrospectorを追加すると、オブジェクトのどのメソッドをプロパティとして扱うかの挙動を変えることができるようになっています。
使い方はテストコードがあるので、そちらを見てみます。
String[] properties = { "test", "other", "oneMore" };
SuppressPropertiesBeanIntrospector introspector = new SuppressPropertiesBeanIntrospector(
Arrays.asList(properties));
単にプロパティとして扱いたくないものの名前をコンストラクタで渡すだけです。
getClassをプロパティとして扱わないようにする
さて、Struts1の脆弱性の原因であったこの問題に対処してみます。SuppressPropertiesBeanItrospectorに専用のSUPPRESS_CLASSがあるので、これをPropertyUtilsのaddIntrospectorに渡すだけです。
Map<String, String> desc1 = BeanUtils.describe(new TestBean());
assertNotNull(desc1.get("class"));
BeanUtils.getProperty(new TestBean(), "class");
PropertyUtils.addBeanIntrospector(
SuppressPropertiesBeanIntrospector.SUPPRESS_CLASS);
PropertyUtils.clearDescriptors();
Map<String, String> desc2 = BeanUtils.describe(new TestBean());
assertNull(desc2.get("class"));
try {
BeanUtils.getProperty(new TestBean(), "class");
fail("Could access class property");
} catch(NoSuchMethodException ex) {
// ok
}
}
これで、classがプロパティ扱いされなくなります。populateもdescribeもgetProperty/setPropertyもOKです。
Webアプリで使うときは、Resolverでの対処と同じように、ServletListenerに入れ込めばよいです。
package example;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.SuppressPropertiesBeanIntrospector;
public class SuppressPropertiesListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
PropertyUtils.addBeanIntrospector(
SuppressPropertiesBeanIntrospector.SUPPRESS_CLASS);
PropertyUtils.clearDescriptors();
}
@Override
public void contextDestroyed(ServletContextEvent event) {
}
}
本家の公式なので、まぁ一番キレイに対応できますね。