Spring Boot 2.1.x の Web アプリを 2.2.x へバージョンアップする ( その10 )( SpotBugs プラグインの findsecbugs-plugin を導入する )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- SpotBugs Pluginを利用する で見かけた SpotBugs プラグインの Find Security Bugs を導入します。
参照したサイト・書籍
- Find Security Bugs
https://find-sec-bugs.github.io/
目次
- build.gradle を変更する
- 検知された警告に対応する
- 整合性のない暗号(暗号はデータの整合性を提供していません。)
- Spring の制限のない RequestMapping による CSRF(Spring の制限のない RequestMapping は,このメソッドを CSRF 攻撃 に対して脆弱にします。)
- Information Exposure Through An Error Message(Information Exposure Through An Error Message)
- ログの潜在的な CRLF インジェクション(org/slf4j/Logger.info(Ljava/lang/String;)V を使用すると CRLF 文字をログメッセージに含めることができます。)
- Freemarker の潜在的なテンプレートインジェクション(Freemarker テンプレートの潜在的なテンプレートインジェクションです。)
- ハードコードされたパスワード(ハードコードされたパスワードを発見)
手順
build.gradle を変更する
dependencies { .......... // for SpotBugs compileOnly("com.github.spotbugs:spotbugs:${spotbugsVersion}") compileOnly("net.jcip:jcip-annotations:1.0") compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsVersion}") testImplementation("com.google.code.findbugs:jsr305:3.0.2") spotbugsStylesheets("com.github.spotbugs:spotbugs:${spotbugsVersion}") spotbugsPlugins("com.h3xstream.findsecbugs:findsecbugs-plugin:1.10.1") }
- dependencies block に
spotbugsPlugins("com.h3xstream.findsecbugs:findsecbugs-plugin:1.10.1")
を追加します。
Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると "BUILD SUCCESSFUL" のメッセージは出力されましたが、The following classes needed for analysis were missing:
と SpotBugs rule violations were found. See the report at: ...
のメッセージも出力されました。
The following classes needed for analysis were missing:
のメッセージについては Lambda methods reported as missing classes の Issue が上がっていますが、まだ Open の状態でしたので今回は特に何もしません。
SpotBugs rule violations were found. See the report at: ...
のメッセージの方はレポートファイルを開くと High Priority Warnings
が 27件、Medium Priority Warnings
が 4件検知されていました。1つずつ見て対応します。
検知された警告に対応する
整合性のない暗号(暗号はデータの整合性を提供していません。)
レポートファイルに出力されていたのは以下の内容で 1件検知されていました。
findsecbugs-plugin の Bugs Patterns のページで確認したところ Cipher with no integrity のことでした。レポートファイルから Bugs Patterns の該当する Bug Pattern への直接のリンクがないのでちょっと探しずらいですね。
該当箇所 BrowfishUtils.java:[line 38]
を見ると以下のソースで、ECB を使用しているために検知されています。
@SuppressWarnings({"PMD.HardCodedCryptoKey"}) public class BrowfishUtils { .......... private static final String TRANSFORMATION = "Blowfish/ECB/PKCS5Padding"; public static String encrypt(String str) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException , BadPaddingException, IllegalBlockSizeException { .......... Cipher cipher = Cipher.getInstance(TRANSFORMATION); .......... } }
ここでは ECB に脆弱性があることは知っていて使用しているので、BrowfishUtils クラスに @SuppressFBWarnings("CIPHER_INTEGRITY")
を付与して警告が出ないようにします。
@SuppressWarnings({"PMD.HardCodedCryptoKey"}) @SuppressFBWarnings("CIPHER_INTEGRITY") public class BrowfishUtils {
Spring の制限のない RequestMapping による CSRF(Spring の制限のない RequestMapping は,このメソッドを CSRF 攻撃 に対して脆弱にします。)
レポートファイルに出力されていたのは以下の内容で 26件検知されていました。
findsecbugs-plugin の Bugs Patterns のページで確認したところ Spring CSRF unrestricted RequestMapping のことでした。
これは指摘された通りなので、以下のように対応します。
- 基本的には @RequestMapping ではなく @GetMapping か @PostMapping に変更します。
- 以下のメソッドは GET も POST も受け付ける必要があるので、
@RequestMapping
→@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})
に変更して、SpotBugs の検知対象外になるよう@SuppressFBWarnings("SPRING_CSRF_UNRESTRICTED_REQUEST_MAPPING")
も付与します。- ksbysample.webapp.lending.web.LoginController#index メソッド
- ksbysample.webapp.lending.web.sessionsample.SessionSampleController#index メソッド
Information Exposure Through An Error Message(Information Exposure Through An Error Message)
レポートファイルに出力されていたのは以下の内容で 1件検知されていました。
findsecbugs-plugin の Bugs Patterns のページで確認したところ Information Exposure Through An Error Message のことでした。
該当箇所 ExceptionHandlerAdvice.java:[line 85]
を見ると以下のソースでした。
if (e != null) { try ( StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw) ) { e.printStackTrace(pw); // ← ここ ..........
ここはこのままにします。@SuppressFBWarnings("INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE")
を付与して SpotBugs に検知されないようにします。
@SuppressFBWarnings("INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE") @ExceptionHandler(Exception.class) public ModelAndView handleException(Exception e
ログの潜在的な CRLF インジェクション(org/slf4j/Logger.info(Ljava/lang/String;)V を使用すると CRLF 文字をログメッセージに含めることができます。)
レポートファイルに出力されていたのは以下の内容で 1件検知されていました。
findsecbugs-plugin の Bugs Patterns のページで確認したところ Potential CRLF Injection for logs のことでした。
ログに CRLF が出力されないようにした方が良いらしい。ログは ksbysample.webapp.lending.aspect.logging.RequestAndResponseLogger#logging メソッドで出力しているので、出力時のコードを logger.info(sb.toString());
→ `` に変更して CRLF が出力されないようにします。
private void logging(String title, String name, String value) { StringBuilder sb = new StringBuilder(title); if (name != null) { sb.append(name) .append(" = "); } sb.append(value); logger.info(sb.toString().replaceAll("[\r\n]","")); }
Freemarker の潜在的なテンプレートインジェクション(Freemarker テンプレートの潜在的なテンプレートインジェクションです。)
レポートファイルに出力されていたのは以下の内容で 1件検知されていました。
findsecbugs-plugin の Bugs Patterns のページで確認したところ Potential template injection with Freemarker のことでした。
エンドユーザーが Freemarker のテンプレートを直接編集できる訳ではないので、ksbysample.webapp.lending.helper.freemarker.FreeMarkerHelper#process メソッドに @SuppressFBWarnings("TEMPLATE_INJECTION_FREEMARKER")
を付与して SpotBugs の検知対象外にします。
@SuppressFBWarnings("TEMPLATE_INJECTION_FREEMARKER") private String process(Template template, Map<String, Object> model) {
ハードコードされたパスワード(ハードコードされたパスワードを発見)
レポートファイルに出力されていたのは以下の内容で 1件検知されていました。
findsecbugs-plugin の Bugs Patterns のページで確認したところ Hard coded password のことでした。
該当箇所 WebSecurityConfig.java:[line 163]
を見ると以下のソースでした。
@SuppressWarnings("PMD.SignatureDeclareThrowsException") @Autowired public void configAuthentication(AuthenticationManagerBuilder auth , ApplicationEventPublisher applicationEventPublisher) throws Exception { auth.inMemoryAuthentication() .withUser(ACTUATOR_USERNAME) .password("{noop}xxxxxxxx") // ←ここ .roles("ENDPOINT_ADMIN"); auth.authenticationEventPublisher(new CustomAuthenticationEventPublisher(applicationEventPublisher)) .userDetailsService(userDetailsService); }
ここは故意に平文でパスワードを書いているので、@SuppressFBWarnings("HARD_CODE_PASSWORD")
を付与して SpotBugs の検知対象外にします。
@SuppressWarnings("PMD.SignatureDeclareThrowsException") @SuppressFBWarnings("HARD_CODE_PASSWORD") @Autowired public void configAuthentication(AuthenticationManagerBuilder auth , ApplicationEventPublisher applicationEventPublisher) throws Exception {
以上の対応で SpotBugs で何も検知されなくなりました。
今回導入してみて思いましたが、SpotBugs を入れるなら findsecbugs-plugin も合わせて入れた方がいいですね。
履歴
2020/01/05
初版発行。