javax.net.ssl.SSLHandshakeException - Received fatal alert - handshake_failure 邮件发送失败
2017, Jan 17
今天在写邮件发送的时候,报了一个错误javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
。
看字面上意思应该是握手失败。查了一些资料,是因为Java8开始禁用了 RC4 加密方式。而刚刚好,QQ的服务器用的就是这种方式。 这就很尴尬了,最后找到两个方法来解决这个问题。
方法一、 跳过 JCE(java加密组件) API 参考stackoverflowlink
这种方法比较简单, 之间在发送邮件之前执行下列方法即可, 这个方法会判断如果是Oracle的jre,就会通过反射跳过JCE API的执行。
public static void removeCryptographyRestrictions() {
if (!isRestrictedCryptography()) {
return;
}
try {
/*
* Do the following, but with reflection to bypass access checks:
*
* JceSecurity.isRestricted = false;
* JceSecurity.defaultPolicy.perms.clear();
* JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
*/
final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");
final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
isRestrictedField.setAccessible(true);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
isRestrictedField.set(null, false);
final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
defaultPolicyField.setAccessible(true);
final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);
final Field perms = cryptoPermissions.getDeclaredField("perms");
perms.setAccessible(true);
((Map<?, ?>) perms.get(defaultPolicy)).clear();
final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
instance.setAccessible(true);
defaultPolicy.add((Permission) instance.get(null));
} catch (final Exception e) {
}
}
private static boolean isRestrictedCryptography() {
// This simply matches the Oracle JRE, but not OpenJDK.
return "Java(TM) SE Runtime Environment".equals(System.getProperty("java.runtime.name"));
}
方法二 修改jre的java.security文件 参考: 文章
这个方法是说修改 %JAVA_HOME%/jre/lib/java.security
文件
将jdk.tls.disabledAlgorithms=SSLv3, RC4, DH keySize < 768
替换为 jdk.tls.disabledAlgorithms=SSLv3, DH keySize < 768
将jdk.tls.legacyAlgorithms
这个参数里的 RC4_128, RC4_40
删除。
这种方法局限性比较大,因为要修改本地jre内的文件,所以我用的是 方法一
来处理这个问题。
希望这篇文章可以帮到大家。