Сообщение об ошибке
No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
Также выводится как
- javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
Формулировка одна и та же от обновлений JDK 8 до JDK 25. Если JVM работает как сервер и все её собственные протоколы отключены, та же ситуация выглядит как «No appropriate protocol».
Java (JSSE) — the client itself has no enabled protocol/cipher combination left
Что это означает
JVM не смогла даже сформировать ClientHello: после исключения всех протоколов и наборов шифров, перечисленных в jdk.tls.disabledAlgorithms, от запрошенного приложением ничего не осталось. Обычно код или конфигурация требуют TLS 1.0, TLS 1.1 или SSLv3, а все они отключены в современных JDK. На сервер ничего не отправлялось.
Почему это происходит
Приложение принудительно задаёт старый протокол
частоSSLContext.getInstance("TLSv1"), setEnabledProtocols(new String[]{"TLSv1"}) или https.protocols=TLSv1, прописанные много лет назад ради старого сервера.
Обновление JDK отключило то, на чём работало приложение
частоTLS 1.0 и 1.1 отключены по умолчанию в обновлениях безопасности Java 8, 11 и более поздних версий, вышедших в 2021 году; приложения, которые работали только с ними, после обновления перестают работать.
Явно заданный список наборов шифров содержит только отключённые наборы
иногдаЕсли в конфигурации перечислено лишь несколько наборов TLS_RSA_* или 3DES, после их отключения не остаётся ничего пригодного.
Как исправить
- 1.
Найдите, где запрашивается старый протокол
Поищите явные названия протоколов в коде и параметрах JVM; -XshowSettings:security:tls показывает, что включено в JDK.
bash grep -rnE 'SSLContext.getInstance\("(TLSv1|TLSv1\.1|SSL)"\)|setEnabledProtocols|https\.protocols' src/ java -XshowSettings:security:tls -version 2>&1 | sed -n '/Enabled Protocols/,/Enabled Cipher/p' - 2.
Запрашивайте «TLS» и доверьте согласование JSSE
В современных JDK SSLContext.getInstance("TLS") включает TLS 1.3 и 1.2.
java // Let JSSE negotiate the best version (TLS 1.3 / 1.2) SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(null, null, null); - 3.
Крайняя мера: точечное переопределение для одного устаревшего эндпоинта
Если устройство нельзя обновить, отдельный файл свойств безопасности может убрать TLSv1/TLSv1.1 из jdk.tls.disabledAlgorithms для той JVM, которая с ним работает. Возьмите за основу полное текущее значение из JDK, измените только записи о протоколах и изолируйте эту JVM.
bash # Last resort for ONE legacy endpoint: take this JDK's own value and drop only TLSv1/TLSv1.1 v=$(sed -n '/^jdk.tls.disabledAlgorithms=/,/[^\\]$/p' "$JAVA_HOME/conf/security/java.security" | sed 's/\\$//' | tr -d '\n') printf '%s\n' "$v" | sed -E 's/ TLSv1(\.1)?,//g' > legacy-tls.security java -Djava.security.properties=legacy-tls.security -jar legacy-client.jar