Https之安全Socket

概述

最近在做Https和wss安全连接,它们都是基于安全套接字SSLSocket的。
我们知道,网络协议是分层次的,从HTTP ->TCP/UDP ->IP ->MAC层,实现了对数据的封装和分发。而套接字Socket,实际上是以门面模式实现对TCP/IP协议的封装。所谓安全Socket,即在Socket上实现身份认证和网络通道加密。在建立连接的过程中,可以使用证书进行身份验证(客户端对服务器的身份验证,或者相互验证),并生成后续连接通道上对称加密的密钥(通过在握手过程中产生的三个随机数和约定好的密钥算法),从而建立安全的连接。而这个安全连接,实际上,就是http区别https,ws区别wss的重点和关键。

运行机制

基于安全套接字的通信,它背后的运行机制是这样的:

  • 生成公钥和私钥对。通常,服务器对保存私钥,并保证它不会被窃取,然后将公钥分发给客户端。客户端使用公钥对内容进行加密,然后服务器使用私钥进行解密。非堆成加密方式是十分安全的,并且,只要私钥能够对公钥加密过的内容解密。
  • 公钥通常存储在证书中,服务器以证书的方式分发。一般的证书格式为X509标准。这个证书,可以是自制的,也可以是机构颁发的。自己颁发的证书会存在安全隐患,即在分发的过程中,可能被中间服务器拦截,同时中间服务器向客户端分发了自己的证书,代替正常服务器和客户端通信。这就是“中间人攻击”。所以,通常我们会选择可信机构颁发的证书。 这样,客户端会从可信机构查询验证证书的有效性和安全性。
  • 在握手过程中,会产生三个随机数。第一个随机数是客户端发给服务器的;第二个随机数是客户端通过公钥进行加密后发给服务器的;第三个随机数是在服务器上生成发给客户端的,这样客户端和服务器将使用这个三个随机数和加密算法,生成后续通信过程中要使用的对称加密密匙。至于为啥最终要使用进行对称加密,原因我想有二:1. 非对称加密,是CPU密集型运算,耗费资源,同时拖慢访问速度;2.后面再约定好对称加密密钥,该密钥是根据算法和随机参数生成的,具有临时性,随机性,能够有效保证安全,同时,相对非对称加密会快很多。

获取安全Socket

SSLContext这个类是对安全套接字协议的实现,并扮演了一个安全套接字工厂的角色。我们可以通过

SSLContext context = SSLContext.getInstance(String protocol)

来获得一个SSLContext实例,其中参数为protocol,即要使用的协议名。这些协议名可以是SSL,TLS(其中TLS是SSL的继任者,TLS1.0相当于SSL3.1)等。
通过SSLContext实例,我们可以得到SSLSocketFactory或者SSLServerSocketFactory, 从而最终获取客户端使用的SSLSocket和相对应的服务器所使用的SSLServerSocket。

SSLContext context = SSLContext.getInstance(String protocol)
//初始化context
context.init((KeyManager[] km, TrustManager[] tm,
                                SecureRandom random));
//在服务器端,需要获取安全的ServerSocket
SSLServerSocketFactory serverFactory = context.getServerSocketFactory();
SSLServerSocket serverSocket = serverFactory.getServerSocket(···) ;
//在客户端,需要获取安全的Socket
SSLSocketFactory clientFactory= context.getSocketFactory();
SSLSocket clientSocket= clientFactory.createSocket(···);

拿到SSLSocket和SSLServerSocket,实际上我们已经可以直接在服务器和客户端之间进行通信了。
重点关注上面的 init 过程。

context.init((KeyManager[] km, TrustManager[] tm,
                                SecureRandom random));
  • km:用于管理自己的key,包括证书和私钥。用途一般就是身份验证和信息加密。
  • tm : 主要用于处理身份验证。即验证是否为我们需要进行通信的服务器。如果我们在本地存有公钥,那么从服务器获取证书后,从证书中取出公钥和本地存的公钥对比,即可验证服务器,而非中间攻击服务器。通常,继承该类,重新其中的重要方法checkServerTrusted。
  • random :随机数生成器。

单向认证和双向认证

如果服务器不需要根据证书验证客户端身份的合法性,那么通常在客户端中,km设置为null,主要通过tm验证服务器的合法性;
如果需要设置双向认证,则需要在本地km管理本地key,即不为空。
无论如何对tm和km设置,我们注意到它们的工厂类初始化过程,都需要传入keystore,但是这两个KeyStore是有区别的。

//得到TrustManager
KeyStore trustKeyStore= KeyStore.getInstance(KeyStore.getDefaultType());
trustKeyStore.setCertificateEntry(certificateAlias,
            certificateFactory.generateCertificate(certificate));
trustManagerFactory.init(trustKeyStore);
trustManager = trustManagerFactory.getTrustManagers();
//得到KeyManager
clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(mContext.getAssets().open("client.bks"),
            "123456".toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
            KeyManagerFactory.
            getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, "123456".toCharArray());

KeyManager实际上管理的是自己的KeyStore,而TrustManager管理的是对方的KeyStore。自己的KeyStore可以用来让对方验证自己的身份,而对方的KeyStore用来验证对方身份的合法性。

应用于OkHttp3中

客户端单向验证

sslContext.init(
                null,
                trustManagerFactory.getTrustManagers(),
                new SecureRandom()
                 );
defaultSslSocketFactory = sslContext.getSocketFactory() ;
okHttpClient = new OkHttpClient.Builder()
                .readTimeout(10,TimeUnit.SECONDS)
                .writeTimeout(10,TimeUnit.SECONDS)
                .connectTimeout(10,TimeUnit.SECONDS)
                .cache(cache)
                .sslSocketFactory(defaultSslSocketFactory)
        //        .addInterceptor(new LoggingInterceptor())
                .build();

证书生成

keytool -genkey -alias server -keyalg RSA 
        -keystore server.jks -validity 3600 
        -storepass 123456 
        -ext san=ip:10.2.10.26(服务器ip)
    
keytool -export -alias server 
        -file server.cer 
        -keystore server.jks 
        -storepass 123456

Tomcat服务器端配置


import java.io.IOException;
import java.util.ArrayList;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value = "/wschat")
public class WebSocketServlet {
    //notice:not thread-safe
    private static ArrayList<Session> sessionList = new ArrayList<Session>();
    
    @OnOpen
    public void onOpen(Session session){
        System.out.println("WebSocket Obj:"+this.toString());
        System.out.println("---onOpen---");
        try{
            sessionList.add(session);
            //asynchronous communication
            session.getBasicRemote().sendText("Hello!");
        }catch(IOException e){}
    }
    
    @OnClose
    public void onClose(Session session){
        sessionList.remove(session);
    }
    
    @OnMessage
    public void onMessage(String msg){
        System.out.println("---onMsg---"+msg);
        try{
            for(Session session : sessionList){
                //asynchronous communication
                session.getBasicRemote().sendText(msg);
            }
        }catch(IOException e){
            System.out.println("exception onMsg");
        }
    }
}

server.xml中connector配置:

<Connector
           protocol="org.apache.coyote.http11.Http11NioProtocol"
           port="8443" maxThreads="200"
           maxHttpHeaderSize="8192"
           scheme="https" secure="true" SSLEnabled="true"
           keystoreFile="D:\\apache-tomcat-8.5.15-windows-x64\\apache-tomcat-8.5.15\\conf\\server.jks" keystorePass="123456"
           clientAuth="false" sslProtocol="TLS"/>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,302评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,563评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,433评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,628评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,467评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,354评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,777评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,419评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,725评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,768评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,543评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,387评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,794评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,032评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,305评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,741评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,946评论 2 336

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,517评论 18 139
  • 原文地址 http://blog.csdn.net/u012409247/article/details/4985...
    0fbf551ff6fb阅读 3,505评论 0 13
  • 一、作用 不使用SSL/TLS的HTTP通信,就是不加密的通信。所有信息明文传播,带来了三大风险。 (1)窃听风险...
    XLsn0w阅读 10,465评论 2 44
  • 最近工作中使用到了一些加密的算法,如: 对称加密的DES、3DES、RC4、AES 非对称加密算法:RSA,DSA...
    郭之源阅读 2,139评论 0 12
  • 本文转载,出处如下:数字证书原理 文中首先解释了加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明了...
    随安居士阅读 1,668评论 1 8