http升级https改造方案

时间:2024-03-06 19:45:28

 

一、解决方案

1、httpClient请求https版蓝鲸接口

1)、原理

https与http最大的区别在于SSL加密传输协议的使用。在自己写的JAVA HttpClient程序,想手动验证证书,可以在客户端绕过验证服务器证书的步骤,即则需要实现空的X509TrustManager接口。

类中的验证方法返回void或者null,是为了绕过验证。正常的方法体如果检验出证书无法被信任,需要手动抛出异常:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building

failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

并在chtch中处理异常,如果想要绕过验证,也就是说不要抛出异常就可以了,可以理解为信任了任何证书。

2)、代码展示:HttpsClientUtil.java

 

import org.apache.http.client.HttpClient;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
/**
 * @author xiehaiqing
 * @date 2019/03/26
 */
public class HttpsClientUtil {
    /**
     * 在调用SSL之前需要重写验证方法,取消检测SSL
     * 创建ConnectionManager,添加Connection配置信息
     * @return HttpClient 支持https
     */
    public static HttpClient sslClient(){
        try {
            // 在调用SSL之前需要重写验证方法,取消检测SSL
            X509TrustManager trustManager = new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
                        throws CertificateException { }
                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
                        throws CertificateException { }
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
            ctx.init(null, new TrustManager[]{trustManager}, null);
            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
            //创建registry
            RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT)
                    .setExpectContinueEnabled(Boolean.TRUE).setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
                    .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)).build();
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", socketFactory).build();
            // 创建ConnectionManager,添加Connection配置信息
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            CloseableHttpClient closeableHttpClient = HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig).build();
            return closeableHttpClient;
        }catch (KeyManagementException ex){
            throw new RuntimeException(ex);
        }catch (NoSuchAlgorithmException e){
            throw new RuntimeException(e);
        }
    }

    /**
     * post请求
     * @param url
     * @param jsonStr
     * @return
     */
    public static String doPost(String url,String jsonStr){
        HttpClient httpClient = null;
        HttpPost httpPost = null;
        String result = null;
        try{
            httpClient = sslClient();
            httpPost = new HttpPost(url);
            httpPost.addHeader("Content-type","applicattion/json");
            StringEntity se = new StringEntity(jsonStr);
            se.setContentType("text/json");
            se.setContentEncoding(new BasicHeader("Content-type","application/json"));
            httpPost.setEntity(se);
            HttpResponse response = httpClient.execute(httpPost);
            if (response !=null){
                HttpEntity entity = response.getEntity();
                if (entity !=null){
                    result = EntityUtils.toString(entity,"utf-8");
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
}
View Code

 

 

 

 展开源码 

2、模拟https版本登录

1)、原理

icube模拟登陆,即是通过服务的登录链接,对用户输入的账号密码进行真实的验证,本功能使用了Jsoup解析的方式实现。

具体逻辑为,先使用get请求链接的方式,生成登录所需的bklogin_csrftoken这一属性字段,然后在通过post携带用户输入的账号密码和该csrftoken字段进行登录请求,如果用户输入的账号密码正确,则在cookie中会有一个不为空的bk_token字段,即为登录成功,否则登录失败。对于https请求,需要在请求之前绕过证书验证,这里采用创建不验证证书链的信任管理器来实现。

登录链接示例:https://xx.com/login/?c_url=

2)代码展示

 

  1 import com.zork.opbd.datasource.Config;
  2 
  3 import com.zork.opbd.log.SystemLogHelper;
  4 
  5 import org.jsoup.Connection;
  6 
  7 import org.jsoup.Connection.*;
  8 
  9 import org.jsoup.Jsoup;
 10 
 11 import org.jsoup.nodes.Document;
 12 
 13 import org.jsoup.nodes.Element;
 14 
 15 import org.jsoup.select.Elements;
 16 
 17  
 18 
 19 import javax.net.ssl.*;
 20 
 21 import java.security.KeyManagementException;
 22 
 23 import java.security.NoSuchAlgorithmException;
 24 
 25 import java.security.SecureRandom;
 26 
 27 import java.security.cert.CertificateException;
 28 
 29 import java.security.cert.X509Certificate;
 30 
 31 import java.util.*;
 32 
 33 
 34 
 35 public class BKLoginUtils {
 36 
 37     public static String LOGIN_URL= Config.getInstance().BK_LOGIN_URL; //https://xx.com/login/?c_url=
 38 
 39     public final static String USER_AGENT="User-Agent";
 40 
 41     public final static String USER_AGENT_VALUE="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36";
 42 
 43     public final static String LOGINFORM = "#login-form";
 44 
 45     public final static String NAME = "name";
 46 
 47     public final static String VALUE = "value";
 48 
 49     public final static String USERNAME = "username";
 50 
 51     public final static String PASSWORD = "password";
 52 
 53     public final static String ID = "id";
 54 
 55     public final static String USER = "user";
 56 
 57     public final static String REFERER = "Referer";
 58 
 59     public final static String BKTOKEN = "bk_token";
 60 
 61  
 62 
 63  
 64 
 65     public static void main(String[] args) throws Exception {
 66 
 67         boolean admin = siMulateLogin("admin", "zork.8888");
 68 
 69         System.out.println(admin);
 70 
 71     }
 72 
 73  
 74 
 75     /**
 76 
 77      * 模拟登陆功能
 78 
 79      * @param userName
 80 
 81      * @param pwd
 82 
 83      * @return result
 84 
 85      */
 86 
 87     public static boolean siMulateLogin(String userName,String pwd){
 88 
 89         boolean result = false;
 90 
 91         try{
 92 
 93             checkQuietly();
 94 
 95             Connection con = Jsoup.connect(LOGIN_URL).timeout(30000).userAgent(USER_AGENT_VALUE);
 96 
 97             Response rs = con.execute();
 98 
 99             Document doc = Jsoup.parse(rs.body());
100 
101             List<Element> elements = doc.select(LOGINFORM);
102 
103             Elements allElements = elements.get(0).getAllElements();
104 
105             Iterator<Element> iterator = allElements.iterator();
106 
107             Map<String,String> datas = new HashMap<>();
108 
109             while (iterator.hasNext()){
110 
111                 //赋值
112 
113                 Element element = iterator.next();
114 
115                 if (element.attr(NAME).equals(USERNAME) && element.attr(ID).equals(USER)){
116 
117                     element.attr(VALUE,userName);
118 
119                 }
120 
121                 if (element.attr(NAME).equals(PASSWORD) && element.attr(ID).equals(PASSWORD)){
122 
123                     element.attr(VALUE,pwd);
124 
125                 }
126 
127                 //排除空值表单属性
128 
129                 if (element.attr(NAME).length()>0){
130 
131                     datas.put(element.attr(NAME),element.attr(VALUE));
132 
133                 }
134 
135             }
136 
137             Connection conn = Jsoup.connect(LOGIN_URL);
138 
139             conn.header(USER_AGENT,USER_AGENT_VALUE);
140 
141             conn.header(REFERER,LOGIN_URL);//注意,这一行必须要加,否则会验证失败
142 
143             Response login = conn.ignoreContentType(true).followRedirects(true).method(Method.POST).data(datas).cookies(rs.cookies()).execute();
144 
145             Map<String,String> cookies = login.cookies();
146 
147             Iterator<String> keyIter = cookies.keySet().iterator();
148 
149             while (keyIter.hasNext()){
150 
151                 String key = keyIter.next();
152 
153                 if (BKTOKEN.equals(key)){
154 
155                     if (!StringUtil.isNull(cookies.get(key))){
156 
157                         SystemLogHelper.info("获取bk_token成功,bk_token:"+cookies.get(key),true);
158 
159                         result = true;
160 
161                     }else {
162 
163                         SystemLogHelper.info("获取bk_token失败,登陆失败,请检查用户名或密码",true);
164 
165                     }
166 
167                 }
168 
169             }
170 
171         }catch (Exception e){
172 
173             e.printStackTrace();
174 
175         }
176 
177         return result;
178 
179     }
180 
181  
182 
183  
184 
185     /**
186 
187      * 信任管理器
188 
189      * 绕过证书验证
190 
191      */
192 
193     public static void checkQuietly(){
194 
195         try{
196 
197             //创建不验证证书链的信任管理器
198 
199             TrustManager[] trustAllCerts = {
200 
201                     new X509TrustManager() {
202 
203                         @Override
204 
205                         public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
206 
207  
208 
209                         }
210 
211                         @Override
212 
213                         public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
214 
215  
216 
217                         }
218 
219                         @Override
220 
221                         public X509Certificate[] getAcceptedIssuers() {
222 
223                             return null;
224 
225                         }
226 
227                     }
228 
229             };
230 
231             //安装所有的信任管理器
232 
233             SSLContext ssl = SSLContext.getInstance("SSL");
234 
235             ssl.init(null,trustAllCerts,new SecureRandom());
236 
237             HttpsURLConnection.setDefaultSSLSocketFactory(ssl.getSocketFactory());
238 
239             //不验证主机名
240 
241             HostnameVerifier hv = new HostnameVerifier() {
242 
243                 @Override
244 
245                 public boolean verify(String s, SSLSession sslSession) {
246 
247                     return true;
248 
249                 }
250 
251             };
252 
253             HttpsURLConnection.setDefaultHostnameVerifier(hv);
254 
255         } catch (NoSuchAlgorithmException | KeyManagementException e) {
256 
257             e.printStackTrace();
258 
259         }
260 
261  
262 
263     }
264 
265 }
View Code