内容简介:本篇文章只涉及本人在工作上使用HttpClient遇到的情况,并不会详细地展开讲如何使用HttpClient.一开始其实是考虑使用RestTemplate的,但遇到的难题自然是SSL认证以及NTLM的认证.以目前的RestTemplate还做不到NTLM认证.而且使用SSL认证的过程也是挺复杂的.至于为什么要绕过SSL认证,因为装证书的这些操作我并不会.同时也想试试能不能忽略这个证书认证调用接口.
本篇文章只涉及本人在工作上使用HttpClient遇到的情况,并不会详细地展开讲如何使用HttpClient.
1. 为什么使用HttpClient?
一开始其实是考虑使用RestTemplate的,但遇到的难题自然是SSL认证以及NTLM的认证.以目前的RestTemplate还做不到NTLM认证.而且使用SSL认证的过程也是挺复杂的. 复杂的是:居然还是要借助HttpClient .
@Bean public RestTemplate buildRestTemplate(List<CustomHttpRequestInterceptor> interceptors) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); factory.setConnectionRequestTimeout(requestTimeout); factory.setConnectTimeout(connectTimeout); factory.setReadTimeout(readTimeout); // https SSLContextBuilder builder = new SSLContextBuilder(); builder.loadTrustMaterial(null, (X509Certificate[] x509Certificates, String s) -> true); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(builder.build(), new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE); Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", new PlainConnectionSocketFactory()) .register("https", socketFactory).build(); PoolingHttpClientConnectionManager phccm = new PoolingHttpClientConnectionManager(registry); phccm.setMaxTotal(200); CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).setConnectionManager(phccm).setConnectionManagerShared(true).build(); factory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(factory); List<ClientHttpRequestInterceptor> clientInterceptorList = new ArrayList<>(); for (CustomHttpRequestInterceptor i : interceptors) { ClientHttpRequestInterceptor interceptor = i; clientInterceptorList.add(interceptor); } restTemplate.setInterceptors(clientInterceptorList); return restTemplate; } 复制代码
2. 为什么要绕过SSL认证?
至于为什么要绕过SSL认证,因为装证书的这些操作我并不会.同时也想试试能不能忽略这个证书认证调用接口.
- 首先如果想绕过证书,都必先创建X509TrustManager这个对象并且重写它的方法.
X509TrustManager该接口是一个用于Https的证书信任管理器,我们可以在这里添加我们的证书,让该管理器知道我们有那些证书是可以信任的.
该接口会有三个方法:
void checkClientTrusted(X509Certificate[] xcs, String str) void checkServerTrusted(X509Certificate[] xcs, String str) X509Certificate[] getAcceptedIssuers() 复制代码
-
第一个方法checkClientTrusted.该方法检查客户端的证书,若不信任该证书则抛出异常。由于我们不需要对客户端进行认证,因此我们只需要执行默认的信任管理器的这个方法。JSSE中,默认的信任管理器类为TrustManager。
-
第二个方法checkServerTrusted.该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。在实现该方法时,也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。
-
第三个方法getAcceptedIssusers,返回受信任的X509证书数组。
而我们只需要重写这三个方法,并且不需要修改里面的内容.然后再交给HttpClient就可以实现绕过SSL认证了.
X509TrustManager trustManager = new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] xcs, String str) { } @Override public void checkServerTrusted(X509Certificate[] xcs, String str) { } SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.SSL); ctx.init(null, new TrustManager[]{trustManager}, null); //生成工厂 SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE); //并注册到HttpClient中 Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", socketFactory).build(); HttpClientBuilder httpClientBuilder = HttpClients.custom().setConnectionManager(connectionManager); CloseableHttpClient httpClient = httpClientBuilder.build(); 复制代码
回顾一下步骤:
- 创建X509TrustManager对象并重写方法.
- 创建SSLContext实例,并交到工厂管理.
- 注册到HttpClient中.通过ConnectionManager最后生成httpClient.
3. 什么是NTLM?
NTLM是NT LAN Manager的缩写,这也说明了协议的来源。NTLM 是 Windows NT 早期版本的标准安全协议,Windows 2000 支持 NTLM 是为了保持向后兼容。Windows 2000内置三种基本安全协议之一。
其实我对这个了解得不是很深,因为遇上这种情况的感觉不会很多,所以网上的资源也不太多. 这里只是针对HttpClient遇上NTLM认证的情况详细描述一下.有兴趣的朋友可以通过以上的链接了解下.
4. 如何使用HttpClient进行NTLM认证?
这个查阅了官网的文档.官网也给出了解决方案.
需要把这几个类编写一下.
JCIFSEngine:
public final class JCIFSEngine implements NTLMEngine { private static final int TYPE_1_FLAGS = NtlmFlags.NTLMSSP_NEGOTIATE_56 | NtlmFlags.NTLMSSP_NEGOTIATE_128 | NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 | NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NtlmFlags.NTLMSSP_REQUEST_TARGET; @Override public String generateType1Msg(final String domain, final String workstation) throws NTLMEngineException { final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation); return Base64.encode(type1Message.toByteArray()); } @Override public String generateType3Msg(final String username, final String password, final String domain, final String workstation, final String challenge) throws NTLMEngineException { Type2Message type2Message; try { type2Message = new Type2Message(Base64.decode(challenge)); } catch (final IOException exception) { throw new NTLMEngineException("Invalid NTLM type 2 message", exception); } final int type2Flags = type2Message.getFlags(); final int type3Flags = type2Flags & (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER)); final Type3Message type3Message = new Type3Message(type2Message, password, domain, username, workstation, type3Flags); return Base64.encode(type3Message.toByteArray()); } } 复制代码
JCIFSNTLMSchemeFactory:
public class JCIFSNTLMSchemeFactory implements AuthSchemeProvider { public AuthScheme create(final HttpContext context){ return new NTLMScheme(new JCIFSEngine()); } } 复制代码
最后就在HttpClient注册:
Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create() .register(AuthSchemes.NTLM, new JCIFSNTLMSchemeFactory()) .register(AuthSchemes.BASIC, new BasicSchemeFactory()) .register(AuthSchemes.DIGEST, new DigestSchemeFactory()) .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory()) .register(AuthSchemes.KERBEROS, new KerberosSchemeFactory()) .build(); CloseableHttpClient httpClient = HttpClients.custom() .setDefaultAuthSchemeRegistry(authSchemeRegistry) .build(); 复制代码
最后就同时使用绕过SSL验证以及NTLM验证:
private static PoolingHttpClientConnectionManager connectionManager; private static RequestConfig requestConfig; private static Registry<AuthSchemeProvider> authSchemeRegistry; private static Registry<ConnectionSocketFactory> socketFactoryRegistry; private static CredentialsProvider credsProvider; public void init() { try { X509TrustManager trustManager = new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] xcs, String str) { } @Override public void checkServerTrusted(X509Certificate[] xcs, String str) { } }; SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.SSL); ctx.init(null, new TrustManager[]{trustManager}, null); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE); NTCredentials creds = new NTCredentials("用户名", "密码", "工作站(workstation)", "域名"); credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials(AuthScope.ANY, creds); socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", socketFactory).build(); connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); connectionManager.setMaxTotal(18); connectionManager.setDefaultMaxPerRoute(6); requestConfig = RequestConfig.custom() .setSocketTimeout(30000) .setConnectTimeout(30000) .build(); authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create() .register(AuthSchemes.NTLM, new JCIFSNTLMSchemeFactory()) .register(AuthSchemes.BASIC, new BasicSchemeFactory()) .register(AuthSchemes.DIGEST, new DigestSchemeFactory()) .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory()) .register(AuthSchemes.KERBEROS, new KerberosSchemeFactory()) .build(); } catch (Exception e) { e.printStackTrace(); } } 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Influxdb 认证绕过漏洞预警
- libSSH 认证绕过漏洞(CVE-2018-10933)分析
- 通过secretkey 绕过flask的session认证
- Cisco IOS软件认证绕过漏洞(CVE-2019-1758)
- 网藤能力中心 | Nuxeo认证绕过和RCE漏洞(CVE-2018-16341) 分析
- 挖洞经验 | HackerOne的双因素认证和上报者黑名单绕过漏洞($10,000)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。