Обновление TLS, ошибка Stackoverflow при использовании CustomHttpsSocketFactory

С помощью этой ссылки пытались выполнить обновление до TLSv1.2. Единственная разница заключалась в том, что до сих пор поддерживались все TLS, поэтому использовали это:

sslSocket.setEnabledProtocols(new String[]{"TLSv1","TLSv1.1","TLSv1.2"});

Странно было получить эту ошибку:

java.lang.StackOverflowError
        at com.myorg.my.utils.Myfile$CustomHttpsSocketFactory.createSocket(Myfile.java:101)

Где Myfile.java имеет такое содержимое, обратите внимание на строку 101, упомянутую ниже:

//...non useful code above
public Myfile(){
        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); 
    }

    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 acceptAllTLS(Socket socket)
       {
          if(!(socket instanceof SSLSocket)) return socket;
          SSLSocket sslSocket = (SSLSocket) socket;
          sslSocket.setEnabledProtocols(new String[]{"TLSv1","TLSv1.1","TLSv1.2"});
          return sslSocket;
       } 
   @Override
   public Socket createSocket(String host, int port) throws IOException
   {
      return acceptAllTLS(base.createSocket(host, port));
   }
   @Override
   public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException
   {
      return acceptAllTLS(base.createSocket(host, port, localAddress, localPort));
   }
   @Override
   public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException
   {
      // The following line is 101 where the error occurs     
      return acceptAllTLS(base.createSocket(host, port, localAddress, localPort, params));
   }
   @Override
   public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException
   {
      return acceptAllTLS(base.createSocket(socket, host, port, autoClose));
   }  // ...non  useful code below}

МОИ ВОПРОСЫ

  1. Кажется очевидным, что base.createSocket рекурсивно вызывает собственный метод. Не могу понять как?

  2. Не удалось реплицировать на моем локальном компьютере, эти журналы существуют только в рабочей среде. Следовательно, как я мог воспроизвести это (использовал ту же версию Java, версию tomcat, версию lib, которая присутствует в производстве)

ИЗМЕНИТЬ

Согласно комментариям трассировка стека:

Вызвано: java.lang.StackOverflowError в com.myorg.my.utils.Myfile$CustomHttpsSocketFactory.createSocket(Myfile.ja> va:101)

Если вы используете JRE8 (если вы не заменили SunJSSE по умолчанию, поставляемый с JRE8), существует системное свойство "jdk.tls.client.protocols". По умолчанию все, что вы здесь укажете, будет использоваться для всех клиентских коммуникаций. Я только что добавил свои комментарии под другой пост, который вы упомянули.


person Danyal    schedule 12.08.2016    source источник
comment
11-е измерение: трассировка стека, «вызванная», повторяет эту строку: в com.myorg.my.utils.Myfile$CustomHttpsSocketFactory.createSocket(Myfile.java:101), около 100 раз и выходы   -  person 11thdimension    schedule 12.08.2016
comment
Нам нужно посмотреть, что произойдет до этого.   -  person Danyal    schedule 12.08.2016
comment
Здесь: java.util.concurrent.ExecutionException: java.lang.StackOverflowError в java.util.concurrent.FutureTask.report(FutureTask.java:122) в java.util.concurrent.FutureTask.get(FutureTask.java:206) в com.myorg.services.SomefileCallingMyMethod$1.getStatusList(SomefileCallingMyMethod.java:519) в com.myorg.services.SomefileCallingMyMethod.getCustomerInfo_aroundBody30(SomefileCallingMyMethod.java:380) в com.myorg.services.IsomefileCallingMyMethod.$AjcClosurev31 Ява: 1)   -  person 11thdimension    schedule 12.08.2016
comment
@Danyal, вместо того, чтобы добавлять трассировку стека в качестве комментария, добавьте ее в сам вопрос :)   -  person Danyal    schedule 12.08.2016
comment
Опубликованная вами трассировка стека не согласуется с опубликованным вами исключением. В трассировке стека нет никаких доказательств того, что _1_ имеет к этому какое-либо отношение. Я полагаю, что у вас есть предыдущая версия кода, работающего в продакшене, с _2_ вместо _3_.   -  person Lahiru    schedule 12.08.2016
comment
EJP, как упоминалось в вопросе, есть «вызвано», что указывает на мой код. Не писал этого снова ранее для краткости. Написал это сейчас. :)   -  person user207421    schedule 13.08.2016
comment
Мой плохой EJP. Как уже упоминалось, я написал исключение ранее в вопросе. Возможно, это было непонятно. опять плохо, извиняюсь   -  person Danyal    schedule 13.08.2016
comment
Я пробовал с этой java -XshowSettings:properties -version, и ссылки на ваше свойство там не было. Спасибо Раджеш в любом случае. Также как это объясняет ошибку Stackoverflow?   -  person Danyal    schedule 13.08.2016


Ответы (3)


У меня была такая же проблема с java.util.concurrent.ExecutionException: java.lang.StackOverflowError.

person Rajesh Jose    schedule 12.08.2016
comment
Код выглядит нормально... Я не вижу в этом рекурсивного вызова. Если бы был какой-либо рекурсивный вызов, он каждый раз вызывал бы переполнение стека. Это могло быть просто случайно, что переполнение стека произошло именно в этот момент... Может быть какой-то поток, в котором слишком много вызовов функций, и случайно он достиг предела стека в этот момент. Если мы не увидим всю трассировку стека, мы не можем этого исключать. Вы также можете проверить размер кадра стека и изменить его, если он слишком мал. Между производством и вашей настройкой также может быть разница в кадре стека. - person Danyal; 12.08.2016
comment
Если jdk.tls.client.protocols не виден, возможно, вы не используете JRE8. Это задокументировано здесь - docs.oracle.com /javase/8/docs/technotes/guides/security/jsse/ - person Rajesh Jose; 12.08.2016
comment
Справедливая точка Раджеш, почти каждый раз. Я пробовал со слишком большим количеством вызовов на моем локальном компьютере, 24 запроса в секунду для 20 тыс. запросов (намного больше, чем ожидалось в моем 1 запросе в секунду в продукте), все еще не мог воспроизвести - person Rajesh Jose; 12.08.2016
comment
Мы используем JRE8 Rajesh :) - person Danyal; 12.08.2016
comment
Количество параллельных запросов не будет иметь никакого значения... Разница может заключаться в среде - например: данные, поступающие в запросе, или данные в модели. Также может иметь значение настроенный размер кадра стека (-Xss). - person Danyal; 12.08.2016
comment
Не настраивал Xss. В опциях java тоже нет. :( - person Rajesh Jose; 12.08.2016
comment
java.util.concurrent.ExecutionException: java.lang.StackOverflowError в java.util.concurrent.FutureTask.report(FutureTask.java:122) в java.util.concurrent.FutureTask.get(FutureTask.java:206) в com. myorg.cs.aggregator.ciscoivr.services.IvrServiceImpl$1.getStatusList(IvrServiceImpl.java:519) на com.myorg.cs.aggregator.ciscoivr.services.IvrServiceImpl.getCustomerInfo_aroundBody30(IvrServiceImpl.java:380) на com.myorg.cs .aggregator.ciscoivr.services.IvrServiceImpl$AjcClosure31.run(IvrServiceImpl.java:1) в org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(AbstractTransactionAspect.org.aj:66) в transaction.aspectj.AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation(AbstractTransactionAspect.aj:72) в org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(Transac tionAspectSupport.java:281) в org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:70) в com.myorg.cs.aggregator.ciscoivr.services.IvrServiceImpl.getCustomer .java:335) в sun.reflect.GeneratedMethodAccessor660.invoke(неизвестный источник) в sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) в java.lang.reflect.Method.invoke(Method.java:497) в org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302) в org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) в org.springframework.aop.framework.ReflectiveMethodInvocation.proceed( ReflectiveMethodInvocation.java:157) в org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionIn terceptor.java:99) в org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281) в org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) в org.springframework.aop .framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) в org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) в com.sun.proxy. $Proxy156.getCustomerInfo(неизвестный источник) в com.myorg.cs.aggregator.controller.IVRController.getCustomerInfo(IVRController.java:106) в com.myorg.cs.aggregator.controller.IVRController$$FastClassBySpringCGLIB$$e1f912c1.invoke( ) в org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) в org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:718) в org.springframework.aop.framework. ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) на com.myorg.cs.aggregator.interceptor.ResponseTimeInterceptor.invokeUnderTrace(ResponseTimeInterceptor.java:38) на org.springframework.aop.interceptor.AbstractTraceInterceptor.invoke(AbstractTraceInterceptor.java:112) в org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) в org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocatio nProceedingJoinPoint.java:85) в com.myorg.base.aspect.RequestContextProcessingAspect.forwardRequestContext(RequestContextProcessingAspect.java:113) в sun.reflect.GeneratedMethodAccessor419.invoke(неизвестный источник) в sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java: 43) в java.lang.reflect.Method.invoke(Method.java:497) в org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621) в org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod (AbstractAspectJAdvice.java:610) в org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68) в org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168) в org.springframework. aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) в org.springframework.aop.framework.ReflectiveMet hodInvocation.proceed(ReflectiveMethodInvocation.java:179) в org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:654) в com.myorg.cs.aggregator.controller.IVRController$$EnhancerBySpringCGLIB$$a764c904. getCustomerInfo() в sun.reflect.GeneratedMethodAccessor659.invoke(неизвестный источник) в sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) в java.lang.reflect. Method.invoke(Method.java:497) в org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222) в org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java: 137) в org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) в org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMapping.java:HandlerAdapter 814) в org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737) в org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) в org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) в org.springframework.web.servlet.DispatcherServlet.doServ ice(DispatcherServlet.java:893) в org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) в org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) в javax.servlet .http.HttpServlet.service(HttpServlet.java:622) в org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) в javax.servlet.http.HttpServlet.service(HttpServlet.java:729) в org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) в org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) в org.apache.tomcat.websocket.server.WsFilter. doFilter(WsFilter.java:52) в org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) в org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) в org.tuckey .web.filters.urlrewrite.RuleChain.han dleRewrite(RuleChain.java:176) по адресу org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145) по адресу org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92) на org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:381) на org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) на org.apache.catalina.core.ApplicationFilterChain .doFilter(ApplicationFilterChain.java:206) в com.myorg.cs.aggregator.filter. RequestIdentifierFilter.doFilterInternal(RequestIdentifierFilter.java:54) в org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) в org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) в org .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) в org.apache.catalina.filters.CorsFilter.handleNonCORS(CorsFilter.java:438) в org.apache.catalina.filters.CorsFilter.doFilter(CorsFilter .java:179) в org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) в org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) в org.springframework.security. web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:316) в org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126) в o rg.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) в org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) в org.springframework.security. web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) в org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) в org.springframework.security.web.session.SessionManagementFilter.doFilter( SessionManagementFilter.java:122) в org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) в org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) в org .springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) в org.springframework.security.web.servleta pi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:168) в org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) в org.springframework.security.web.savedterCquest.RequestCacheAwareFilterFilter java:48) в org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) в org.springframework.security.web.authentication.logout. LogoutFilter.doFilter(LogoutFilter.java:120) в org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) в org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(Abstract:FilterationProcessing 205) в org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) в org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205framework) в .security.springwork .web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) в org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) в org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.doFilter(OncePerRequestFilter.doFilter(OncePerRequestFilter.doFilter(OncePerRequestFilter.doFilter(OncePerRequestFilter.doFilter) .java:107) в org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(Filt erChainProxy.java:330) в org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) в org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) в org. .springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) в org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) в org.springframework.security.web .FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) в org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213) в org.springframework.security.web.FilterChainProxy.doFilter(Filter.6y:1Proxy ) в org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) в org.springframework.web.filter.DelegatingF ilterProxy.doFilter(DelegatingFilterProxy.java:262) в org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) в org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) в org .apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) в org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) в org.apache.catalina.authenticator. AuthenticatorBase.invoke(AuthenticatorBase.java:502) в org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) в org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) в org , .java:88) в org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) в org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) в org.apache.coyote. AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668) в org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521) в org.apache.tomcat.util.net.NioEndpoint$SocketProcessor. запустить (NioEndpoint.java:1478) в java.util.concurrent .ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) в java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) в org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java :61) на java.lang.Thread.run(Thread.java:745) - person Danyal; 12.08.2016

Загрузчик классов создает private final SecureProtocolSocketFactory base много раз base = CustomHttpsSocketFactory, а рекурсивный вызов метода вызывает StackOverflowError.

В моем случае мой CustomHttpsSocketFactory расширяет SSLProtocolSocketFactory, и проблема исчезает.

У меня такая же проблема. Вы будете регистрировать протокол HTTPS много-много раз. Я думаю, что операция регистрации работает как стек.

person Chinoataku    schedule 11.08.2017

Метод Protocol.registerProptocol должен вызываться один раз в JVM. Каждый registerProtocol вызывает один вызов метода после переполнения стека времени.

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); 

Решение: добавьте синхронизированный метод, например init, и вызовите его.

Пожалуйста, предоставьте трассировку стека.

public static boolean INITIALIZED = false; 

private static synchronized void init() {
    if (!INITIALIZED) {
        INITIALIZED = true;
        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); 
    }
}
...
...
init();
...
...
person oner.unal    schedule 28.02.2018