背景
Spring bootで開発したAPIに対して脆弱性テストを実施した際に、tomcatのエラーページが表示されるケースがあった。
調べた限りでは、Controllerまで到達せずにtomcatのエラーページがHTMLでレスポンスされるようになっており、設定による変更が不可能。エラーページを出力する処理をオーバライドしてカスタマイズすることで回避する方法が提案されていた。
参考のGithub issue
エラーページが表示される例
- URIに使用できない文字が含まれている
http://localhost:8080/api/get/%aaa
- ヘッダに使用できない文字が含まれている
(request): test
実施したいこと
エラーページのカスタマイズは本投稿下部の参考情報をもとに実現できたが、このようなリクエストがあっても必ずしも例外が発生するわけではないようで、エラー時の情報が取得できない。
- リクエストヘッダに異常がある場合はIllegalArgumentExceptionが発生する。
- URIの異常は例外が発生せず、ログに何も出力せずにHTMLをレスポンスしてしまう。
リクエストの情報をログへ出力する方法を調べたところ、オーバライドするErrorReportValve.report()の引数のRequestクラスに含まれる情報が使用できることがわかった。
リクエストヘッダ
@Override
protected void report(final Request request, final Response response, final Throwable throwable){
:
MimeHeaders headers = request.getCoyoteRequest().getMimeHeaders();
for(int i = 0; i < headers.size(); i++){
LOGGER.error(String.format("Request header %s : %s", headers.getName(i), headers.getValue(i)));
}
ただしエラーとなったヘッダについては含まれておらず、受け取ることができたもののみが設定されていると思われる。
例外のトレースにはヘッダ情報が含まれているので、別途出力すれば情報は残すことができる。
if(throwable != null){
LOGGER.error("Request exception", throwable);
}
リクエストURIとクエリストリング
LOGGER.error(String.format("Request URI : %s", request.getCoyoteRequest().requestURI()));
LOGGER.error(String.format("Request querys : %s", request.getCoyoteRequest().queryString()));
出力
[22:11:28 ec2-user ~] curl -H '(request): test' 'http://localhost:8080/api/get/aaaa?a=111&b
=abc' -v
> GET /api/get/aaaa?a=111&b=abc HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
> (request): test
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 400
< Content-Type: text/html;charset=utf-8
< Content-Length: 85
< Date: Sun, 08 Jan 2023 13:11:39 GMT
< Connection: close
<
* Closing connection 0
<!doctype html><html lang="ja"><body>Error</body></html>
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve : Request exception
java.lang.IllegalArgumentException: The HTTP header line [(request): test] does not conform to RFC 7230 and has been ignored.
at org.apache.coyote.http11.Http11InputBuffer.skipLine(Http11InputBuffer.java:1093) ~[tomcat-embed-core-10.1.4.jar:10.1.4]
:
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve : Request header : host : localhost:8080
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve : Request header : user-agent : curl/7.79.1
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve : Request header : accept : */*
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve : Request URI : /api/get/aaaa
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve : Request querys : a=111&b=abc
参考にした情報
エラーページのカスタマイズ方法
https://yukihane.github.io/blog/202105/21/spring-boot-avoid-tomcat-error-page/