Struts 1 の脆弱性に対する対策(Commons BeanUtils 1.8 未満)
import java.lang.reflect.InvocationTargetException;
import java.util.regex.Pattern;
import org.apache.commons.beanutils.BeanUtilsBean;
public class SafeBeanUtilsBean
extends BeanUtilsBean {
private static final String EXLUDE_NAME_REGEX = "(^|\\W)[cC]lass\\W";
private static final Pattern EXLUDE_NAME_PATTERN = Pattern
.compile(EXLUDE_NAME_REGEX);
private static boolean isExcludedName(String name) {
if (name == null) {
return false;
}
return EXLUDE_NAME_PATTERN.matcher(name).find();
}
public void setProperty(Object bean, String name, Object value)
throws IllegalAccessException, InvocationTargetException {
if (isExcludedName(name)) {
return;
}
super.setProperty(bean, name, value);
}
}
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.beanutils.BeanUtilsBean;
public class BeanUtilsBeanListener
implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
BeanUtilsBean.setInstance(new SafeBeanUtilsBean());
}
public void contextDestroyed(ServletContextEvent sce) {}
}
setProperty されなきゃいいんじゃね?ということで書いてみました。
- Struts の脆弱性対策のみならこれで十分っぽい。
- setProperty のみに影響。getProperty 系は対応いらないよね。。。?
- 厳密にやるなら
PropertyUtilsBean
の setProperty 系メソッドの方に対策したほうがいいかも。
(2014/05/16 修正)
EXLUDE_NAME_REGEX は com.opensymphony.xwork2.ExcludedPatterns#CLASS_ACCESS_PATTERN からそのまま持ってきたのですがよくよく見るとどうもおかしいです。
これだと hogeClass.fuga みたいな文字列でもマッチしてしまいます。。。
と思ったら、やはりすでに報告されてました。
https://issues.apache.org/jira/browse/WW-4333
あとは Ignore Case だと cLass みたいなプロパティにもマッチしますね。
というわけで、どちらかと言うとMBSDさんの正規表現のほうがよいのかなあということで修正しました。
パラメータ名に日本語とかを使ってると無視される可能性もありますが現実的にこちらに引っかかるケースのほうが少ないでしょう、ということで。
本来なら Character#isJavaIdentifierPart とかで前後の文字をチェックするのがいいのかもしれません。
他に思いつくとしたら (^|[\.\[\]\(\)"'])[Cc]lass[\.\[\]\(\)"']
こんな感じでしょうか。
これならおそらく BeanUtils で使用可能なプロパティ名は全てカバーできる気がします。
あとは Struts 2.3.18 がリリースされたらもう一度確認してみようと思います。