Apache Struts の脆弱性 (S2-016) に関する注意喚起に対して、struts2のバージョンアップをするのが最善ですが、何らかの事情によりバージョンアップが難しい場合の対応策の一つとして、サーブレット・フィルタによる防御があります。
サーブレット・フィルタのコード
AttackURLParamBlockFilter.java
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain filter) throws IOException, ServletException {
Enumeration<?> params = req.getParameterNames();
while (params.hasMoreElements()) {
String paramName = (String) params.nextElement();
String paramValue = req.getParameter(paramName);
if (isSafetyParam(paramName, paramValue)) {
continue;
}
throw new IllegalArgumentException(
String.format(
"Bad request '%s' was detected.\n",
paramName, paramValue));
}
filter.doFilter(req, res);
}
private static boolean isSafetyParam(String name, String value) {
// S2-016(http://struts.apache.org/development/2.x/docs/s2-016.html)
for (String target : new String[] { name, value }) {
if (target.matches(".*\\%\\{.+\\}.*")
|| target.matches(".*\\$\\{.+\\}.*")) {
return false;
}
}
// S2-017(http://struts.apache.org/development/2.x/docs/s2-017.html)
if (name.matches(".*redirect:.*")
|| name.matches(".*redirectAction:.*")) {
return false;
}
return true;
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
web.xmlの設定
コンパイルして適当に配置し、web.xmlに以下の様に記述する事で、フィルタとして機能します。注意点として、サーブレットフィルタの実行順は、web.xml中に記載したfilter-mappingの順になるという点が挙げられます。
このため、struts2用のフィルタ設定よりも前に、以下の設定を記述する必要があります。
web.xml
<filter>
<filter-name>s2016filter</filter-name>
<filter-class>com.example.s2016filter.AttackURLParamBlockFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>s2016filter</filter-name>
<url-pattern>*</url-pattern>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
効果を確認する
strutsのホームページに記載されている検証用のコードにより効果を確認する事が出来ます。
どのような場合に有効か
struts2のバージョンアップが出来ない場合も、Apacheのmod_rewriteやファイアウォールなどで防御すれば良いだけなので、あまり有効な場面は無いかも知れません。ApacheなどのWebサーバと連携していない場合も、UrlRewriteFilterを利用すれば同じ事が出来ます。