HTTP转免费且安全的HTTPS之路

2020-04-21  本文已影响0人  XJ2017

背景

现有系统是通过http与后端接口交互且使用的是对称秘钥加密用户密码且服务端校验密码通过后也是通过对称密码加密Token(用来客户端签名请求数据)返回给Web前端或APP端,由于秘钥保存在web前端或APP端那都可以通过阅读代码直接获取,故间接暴露用户密码与Token。

思路

其实方案一与方案二都有各种的优劣,可以根据系统特性来选择。由于咱们系统会涉及到资金,就选择了HTTPS。

概念

部署HTTPS服务端

简单HTTPS客户端

强烈建议利用Wireshark查看TCP生命周期中的网络包信息,利用Fiddler拦截HTTP与HTTPS请求并篡改响应数据玩玩。以下是Java版本的简化版https客户端,可以进一步了解https的代码实现。

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;

public class HttpsTest {

    public static void main(String[] args) {
        // 初始化SSL上下文
        initSSLContext();

        try {
            // 设置请求的url
            URL url = new URL("https://test.api.xxx.com/manager/login");
            URLConnection urlConn = url.openConnection();
            urlConn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            // 设置请求的body内容
            urlConn.setDoOutput(true);
            OutputStreamWriter writer = new OutputStreamWriter(urlConn.getOutputStream());
            writer.write("{userName: \"admin\", password: \"666\"}");
            writer.flush();
            writer.close();

            // 执行Https请求并获取响应数据的输入流
            InputStream is = urlConn.getInputStream();
            // 读取响应信息
            BufferedReader in = new BufferedReader(new InputStreamReader(is));
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println("响应数据:" + line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 通过HttpsURLConnection提供的静态方法注册默认的SSLSocketFactory与HostnameVerifier
    public static void initSSLContext() {
        // 初始化TLS协议SSLContext
        SSLContext sslContext;
        try {
            sslContext = SSLContext.getInstance("TLS");
            X509TrustManager[] xtmArray = new X509TrustManager[]{xtm};
            sslContext.init(null, xtmArray, new java.security.SecureRandom());
        } catch (GeneralSecurityException gse) {
            throw new RuntimeException("初始化SSL上下文失败!", gse);
        }

        //为javax.net.ssl.HttpsURLConnection设置默认的SocketFactory和HostnameVerifier
        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    }

    // 利用内部类定义信任所有服务器证书的证书管理器
    private static final X509TrustManager xtm = new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] chain, String authType) {}

        public void checkServerTrusted(X509Certificate[] chain, String authType) {
            System.out.println("证书信息: " + chain[0].toString() + ", 认证方式: " + authType);
        }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };

    // 利用内部类定义主机校验名校验器
    private static final HostnameVerifier hnv = (hostname, session) -> {
        System.out.println("主机信息:" + hostname);
        return true;
    };

}
上一篇 下一篇

猜你喜欢

热点阅读