最近、現場のシステムのSpring Securityのバージョンが上がったせいかコンテキストパスの前に”/”をつけると500エラーを吐くようになってしまった。
ログを見ると初めて見るRequestRejectedExceptionという例外が発生していました。
そこで少し詰まったので備忘録としてメモします。
RequestRejectedExceptionとは?
Spring SecurityではデフォルトでStrictHttpFirewallを使用して不正なリクエストを拒否するようにできています。
例えば
- 許可していないHTTPメソッドを使ったリクエスト
- 正規化されていないURL
- URLにセミコロンを含む
/…/というようなパストラバーサル文字列や//というような連続スラッシュを拒否してくれます。
対象バージョン
Spring SecurityにHttpファイアウォールが追加されたのは
- org.springframework.boot.spring-boot-starter-parentの1.5.10.RELEASE以降
- spring-security-webの4.2.4RELEASE以降
のようです。
これより前のバージョンの人は起きないっぽいです。
実際、私のプロジェクトではバージョンアップするまでは起きていませんでした。
ハンドリングするには
Spring bootには@ControllerAdviceを使用してグローバルな例外をハンドリングできる仕組みがあります。
ただ、今回の例外に関してはコントローラーに到達する前のエラーということで普通のやり方では失敗しました。
調べた結果、RequestRejectedHandlerを実装して、Beanに登録してあげれば例外をハンドリングできるとのこと・・・。
具体的には以下のような感じ。
@Slf4j
public class CustomHttpStatusRequestRejectHandler implements RequestRejectedHandler {
private final int httpError;
public CustomHttpStatusRequestRejectedHandler() {
this.httpError = HttpServletResponse.SC_BAD_REQUEST;
}
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, RequestRejectedException ex) throws IOException {
log.warn(ex.getLocalizedMessage());
response.sendError(this.httpError);
}
}
次に作成したハンドラーをBeanに登録してあげれば完了。
@Bean(name = requestRejectedHandler")
public RequestRejectedHandler requestRejectedHandler() {
return new CustomHttpStatusRequestRejectedHandler();
}
これでRequestRejectedExceptionをハンドリングできるはずです。
お疲れ様でした。
コメント