web-dev-qa-db-fra.com

Comment forcer Commons HTTPClient 3.1 à utiliser TLS 1.2 uniquement pour HTTPS?

Je souhaite forcer Apache Commons HTTP-Client (version .1) à utiliser TLS 1.2 comme le protocole uniquement pour HTTPS.

Cela est dû au fait que le serveur est censé être mis à niveau vers TLS 1.2 et n'accepte plus aucun protocole plus ancien (provoquant le retour de la "réinitialisation de la connexion").

Pour plus de contexte, probablement non pertinent, le client HTTP est utilisé avec Axis2 pour créer un SOAP; une partie du code utilisé pour configurer le HttpClient est ci-dessous:

MultiThreadedHttpConnectionManager connMgr = new MultiThreadedHttpConnectionManager();
this.httpClient = new HttpClient(connMgr);

// initialize HttpClient parameters
HttpClientParams hcParams = this.httpClient.getParams();

// Maximum time to wait to receive connection from pool
hcParams.setConnectionManagerTimeout(this.maxWait);
hcParams.setSoTimeout(this.timeout);
hcParams.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(this.retryCount, false));

// Initialize global Connection manager parameters
HttpConnectionManagerParams cmParams = connMgr.getParams();
cmParams.setDefaultMaxConnectionsPerHost(this.maxActive);
cmParams.setStaleCheckingEnabled(this.checkStaleConnections);
cmParams.setConnectionTimeout(this.timeout);

Merci beaucoup pour l'aide!

21
abdelrahman-sinno

Dommage, personne n'a répondu; J'ai pu le faire, d'abord vous écrivez un CustomHttpSocketFactory, puis vous faites:

String scheme = "https";
Protocol baseHttps = Protocol.getProtocol(scheme);
int defaultPort = baseHttps.getDefaultPort();

ProtocolSocketFactory baseFactory = baseHttps.getSocketFactory();
ProtocolSocketFactory customFactory = new CustomHttpsSocketFactory(baseFactory);

Protocol customHttps = new Protocol(scheme, customFactory, defaultPort);
Protocol.registerProtocol(scheme, customHttps); 

Un exemple de code d'usine de socket personnalisé est trouvé ici , mais à la place je l'ai fait:

public class CustomHttpsSocketFactory implements SecureProtocolSocketFactory
{

   private final SecureProtocolSocketFactory base;

   public CustomHttpsSocketFactory(ProtocolSocketFactory base)
   {
      if(base == null || !(base instanceof SecureProtocolSocketFactory)) throw new IllegalArgumentException();
      this.base = (SecureProtocolSocketFactory) base;
   }

   private Socket acceptOnlyTLS12(Socket socket)
   {
      if(!(socket instanceof SSLSocket)) return socket;
      SSLSocket sslSocket = (SSLSocket) socket;
      sslSocket.setEnabledProtocols(new String[]{"TLSv1.2" });
      return sslSocket;
   }

   @Override
   public Socket createSocket(String Host, int port) throws IOException
   {
      return acceptOnlyTLS12(base.createSocket(Host, port));
   }
   @Override
   public Socket createSocket(String Host, int port, InetAddress localAddress, int localPort) throws IOException
   {
      return acceptOnlyTLS12(base.createSocket(Host, port, localAddress, localPort));
   }
   @Override
   public Socket createSocket(String Host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException
   {
      return acceptOnlyTLS12(base.createSocket(Host, port, localAddress, localPort, params));
   }
   @Override
   public Socket createSocket(Socket socket, String Host, int port, boolean autoClose) throws IOException
   {
      return acceptOnlyTLS12(base.createSocket(socket, Host, port, autoClose));
   }

}
25
abdelrahman-sinno

Vous avez besoin d'une référence Socket dans votre code. Ensuite, vous pouvez définir des protocoles activés comme ceci:

if (socket != null && (socket instanceof SSLSocket)) {
    ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"});
}
2
IgorGanapolsky

Cela dépend de la façon dont vous écrivez vos clients et des versions de JRE que vous utilisez:

Si vous utilisez JRE8 (sauf si vous avez remplacé le SunJSSE par défaut fourni avec JRE8), il existe une propriété système "jdk.tls.client.protocols". Par défaut, tout ce que vous mentionnez ici sera utilisé pour toutes les communications avec les clients.

Si vous utilisez l'objet HttpsURLConnection pour la connexion client, vous pouvez utiliser la propriété système "https.protocols". Cela fonctionnera pour toutes les versions de JRE, pas seulement JRE8.

Si vous ne spécifiez rien, pour les clients TLS, dans JRE8, TLSv1, v1.1 et v1.2 sont activés, il fonctionnera donc avec un serveur qui prend en charge l'une de ces versions. Cependant, dans JRE7 par défaut, TLSv1 seul est activé.

Dans votre code, vous pouvez toujours remplacer la valeur par défaut ou ce que vous passez par les propriétés du système. Ce que vous définissez dans le code aura une priorité plus élevée. Pour remplacer le code ...

1) Si vous utilisez un socket brut et SSLEngine, vous pouvez définir le protocole et les chiffres dans SSLEngine (sslEngine.setEnabledProtocols (..)

2) Si vous utilisez SSLSocket, vous pouvez définir le protocole et les chiffres dans SSLSocket (sslSocket.setEnabledProtocols (..)

Vous pouvez également obtenir un SSLContext avec le protocole requis activé et l'utiliser pour tous les composants SSL que vous utilisez. SSLContext.getInstance ("TLSvx.x"). Notez que par défaut, il renverra un contexte avec tous les protocoles inférieurs à ceux activés par TLSvx.x. Si vous avez configuré "jdk.tls.client.protocols", cela renverra un contexte avec ces protocoles activés.

Ce ne serait pas une bonne idée de coder en dur les protocoles dans le code. Très souvent, nous rencontrerons certains clients qui souhaitent une version spécifique, soit parce qu'ils utilisent d'anciens serveurs, soit que de graves vulnérabilités sont rencontrées dans certaines versions de TLS. Définissez-le via les propriétés système ou même si vous définissez explicitement dans sslsocket ou sslengine, lisez-le dans un fichier conf.

Voir également:

https://docs.Oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html

http://docs.Oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html

2
Rajesh