Django製の Mezzanine で構築されたブログに対して、脆弱性を検証してみる | Monotalk
で、OWASP ZAP を使用して実施した検証を、作成中のアプリケーションに対して実施し、
警告に対して対処していこうと思います。
前提
Wicket × Dropwizard でアプリケーションは構築されています。
まだ日の目を見ておらず、localhost での確認となります。
環境情報
-
OS Version
sw_vers ---------------------------- ProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G1108 ----------------------------
-
Wicket version 7.6.0です。
<dependency> <groupId>org.apache.wicket</groupId> <artifactId>wicket-core</artifactId> <version>7.6.0</version> </dependency>
-
Dropwizard version 1.0.6です。
<dependency> <groupId>io.dropwizard</groupId> <artifactId>dropwizard-core</artifactId> <version>1.0.6</version> </dependency> <dependency> <groupId>io.dropwizard</groupId> <artifactId>dropwizard-servlets</artifactId> <version>1.0.6</version> </dependency> <dependency> <groupId>io.dropwizard</groupId> <artifactId>dropwizard-assets</artifactId> <version>1.0.6</version> </dependency>
検証の内容
-
OWASP ZAP
は デフォルト設定で、プロキシ設定なしの、標準モードで実行
インストールして起動すると表示されるクイックスタートに、
localhost のアプリケーションの URL を入力するだけです。
-
検証対象の URL プロトコルは HTTP
localhost での検証となり、HTTPS での検証はできておりません。 -
TOP 画面に入力項目の有無 入力項目はありません
検証結果に対しての対応方針
- 脆弱性が見つかり、Wicket でも、Dropwizard でも対応できる場合は、Wicket側で対応する。
Dropwizard が、HTTP サーバ× AP サーバのレイヤとなるため、本来 Dropwizard 側での対応が良い気はします。
個人的な興味から、Wicket 側に実装します。
アプリケーションのTOP URL を指定した検証結果
以下の警告が出力されました。
-
X-Frame-Options ヘッダの欠如
-
WebブラウザのXSS防止機能が有効になっていません。
-
X-Content-Type-Optionsヘッダの設定ミス
-
Cross-Domain JavaScript Source File Inclusion
-
Cookie No HttpOnly Flag
対応方法
参考
wicket の user guide の セキュリティ項が参考になりました。1 [1] web 検索ではなぜか上手く hit せず、github の adoc への直リンクとなります。
Wicket で、HttpResponseHeader を設定する
これで以下のヘッダに対する対応が可能です。
-
X-Frame-Options ヘッダの欠如
-
Web ブラウザの XSS 防止機能が有効になっていません。
-
X-Content-Type-Options ヘッダの設定ミス
wicket の user guide に記載されている通り、RequestCycleListener を作成して、
response header の設定処理を実装しました。
-
HttpHeaderAddingRequestCycleListener.java
import org.apache.wicket.request.cycle.AbstractRequestCycleListener; import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.request.http.WebResponse; /** * HttpHeaderAddingRequestCycleListener */ public class HttpHeaderAddingRequestCycleListener extends AbstractRequestCycleListener { private boolean isDeployment; /** * Construct. * * @param isDeployment */ public HttpHeaderAddingRequestCycleListener(boolean isDeployment) { this.isDeployment = isDeployment; } @Override public void onEndRequest(RequestCycle cycle) { WebResponse response = (WebResponse) cycle.getResponse(); response.setHeader("X-XSS-Protection", "1; mode=block"); response.setHeader("X-Content-Type-Options", "nosniff"); response.setHeader("X-Frame-Options", "sameorigin"); // In the deployment mode, the Https related header is set if (isDeployment) { response.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload"); response.setHeader("Content-Security-Policy", "default-src https:"); } } }
-
説明 以下のHeaderについては、localhostで、http通信時は問題がありますので、
Deploymentモードの場合のみ、出力するようにしました。
response.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload"); response.setHeader("Content-Security-Policy", "default-src https:");
Applicationクラスでは以下のように呼び出しています。
getRequestCycleListeners().add(new HttpHeaderAddingRequestCycleListener(usesDeploymentConfig()));
Dropwizard で、HttpResponseHeader を設定する
- X-Content-Type-Options ヘッダの設定ミス
は静的コンテンツ類でも発生しています。
静的コンテンツ類のマウントは、Dropwizard の AssetBundle で実施していて、
このリソースは、Wicket のRequestCycle の制御対象外になります。
こちらは別途 CustomBundle クラスを作成して、Filterでresponse header を設定するようにしました。
以下、記事の実装を参考にさせてもらいました。
-
CORS に対応させるための Servlet Filter - seratch’s weblog in Japanese
-
NoSniffAssetBundle.java
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.setup.Environment;
import org.eclipse.jetty.servlet.FilterHolder;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.EnumSet;
/**
* NoSniffAssetBundle
*/
public class NoSniffAssetBundle extends AssetsBundle {
public NoSniffAssetBundle() {
this("/assets", "/assets", "index.htm", "assets");
}
public NoSniffAssetBundle(String path) {
this(path, path, "index.htm", "assets");
}
public NoSniffAssetBundle(String resourcePath, String uriPath) {
this(resourcePath, uriPath, "index.htm", "assets");
}
public NoSniffAssetBundle(String resourcePath, String uriPath, String indexFile) {
this(resourcePath, uriPath, indexFile, "assets");
}
public NoSniffAssetBundle(String resourcePath, String uriPath, String indexFile, String assetsName) {
super(resourcePath, uriPath, indexFile, assetsName);
}
public void run(Environment environment) {
super.run(environment);
environment.getApplicationContext()
.addFilter(newNoSniffResponseFilterHolder(),
getUriPath(),
EnumSet.of(DispatcherType.ASYNC,
DispatcherType.REQUEST,
DispatcherType.FORWARD,
DispatcherType.INCLUDE,
DispatcherType.ERROR));
}
private FilterHolder newNoSniffResponseFilterHolder() {
FilterHolder holder = new FilterHolder();
holder.setName("NoSniffResponseFilter");
holder.setFilter(new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//Do Nothing...
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("X-Content-Type-Options", "nosniff");
chain.doFilter(request, response);
}
@Override
public void destroy() {
//Do Nothing...
}
});
return holder;
}
}
Cross-Domain JavaScript Source File Inclusion
外部サイトの javascript 読み込みを行っていると、発生する警告です。
こちらの警告発生は許容しました。
Cookie No HttpOnly Flag
これは、jsessionid
が HttpOnly になっていないため、出力されていました。
Dropwizard (というかJetty) の SessionManager
の実装クラスのsetHttpOnly()
で
設定が可能です。
以下の通り、true
を設定しました。
sessionManager.setHttpOnly(true);
env.servlets().setSessionHandler(new SessionHandler(sessionManager));
上記対処で、警告は、
- Cross-Domain JavaScript Source File Inclusion
のみになりました。
以上です。
コメント