RequestRejectedExceptionのハンドリング方法

※当サイトではアフィリエイト広告を利用しています
※当サイトではアフィリエイト広告を利用しています
Java

最近、現場のシステムの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をハンドリングできるはずです。

お疲れ様でした。

コメント

タイトルとURLをコピーしました