Java安全之SSL/TLS

article/2025/10/8 22:08:16

   在前面所讲到的一些安全技术手段如:消息摘要、加解密算法、数字签名和数据证书等,一般都不会由开发者直接地去使用,而是经过了一定的封装,甚至形成了某些安全协议,再暴露出一定的接口来供开发者使用。因为直接使用这些安全手段,对开发者的学习成本太高,需要深入了解底层实现才行,而直接使用封装后暴露出来的接口就容易多了。

   在这些封装与协议的背后,很多都使用到了SSL/TSL协议,其中最常见的HTTPS就是在HTTP协议的基础上加入了SSL/TLS协议形成的,来保障Web访问安全性。SSL/TLS协议包含两个协议:SSL(Secure Socket Layer,安全套接字层)和TLS(Transport Layer Security,传输层安全)协议。SSL由Netscape公司研发,位于TCP/IP参考模型中的网络传输层,作为网络通讯提供安全及数据完完整性的一种安全协议。TLS是基于SSL协议之上的通用化协议,它同样位于TCP/IP参考模型中的网络传输层,作为SSL协议的继承者,成为下一代网络安全性与数据完整性安全协议。

   SSL/TLS协议的具体实现与细节肯定是很复杂的,可以百度一下慢慢了解,下面主要列举一下Java中经常遇见的与SSL/TLS有关的情况:

一、Tomcat中HTTPS协议的配置

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true"maxThreads="150" scheme="https" secure="true"clientAuth="true" sslProtocol="TLS" keystoreFile="conf/serverKeyStore.jks"keystorePass="gitblit"truststoreFile="conf/caKeyStore.p12"truststorePass="gitblit"truststoreType="pkcs12"/>


属性解释:
port:协议监听端口号
protocol: 协议实现类
maxThreads: 最大线程数
SSLEnabled,scheme,secure,sslProtocol:基本上是固定配置
keystoreFile:服务器KeyStore文件路径
keystorePass:服务器KeyStore密码
clientAuth:是否验证客户端
truststoreFile:服务器信任KeyStore文件路径
truststorePass:服务器信任KeyStore密码
truststoreType:服务器信任KeyStore类型,如不指定,默认为jks

   在服务器KeyStore文件中最好只有一个条目,当然条目为KeyEntry类型,因为在该配置中无法配置被用于安全通信的条目别名,如果有多个条目的话,服务器会任意选行一个条目,就会造成所使用条目不确定的情况。服务器信任KeyStore中存储的条目是CertificateEntry类型,正确情况下里面只存储了服务器信任的证书。一般说来这些证书都是有一根证书颁发给客户端使用的,而这个根证书肯定是服务器所有的,所以服务器信任KeyStore中最好只存储一个为客户端颁发证书的根证书,这样只要信任了该根证书,也就会信任该根证书颁发的所有证书,利于添加新的客户端。当然还有一种更笨的做法就是将根证书颁发给客户端使用的证书全部添加到服务器信任KeyStore文件中。如果clientAuth配置为false,即单向认证,只认证服务端而不,而不认证客户端,那么,truststoreFile,truststorePass,truststoreType这几个属性是用不上的,可不配置。

二、SSLSocket的使用

package com.xtayfjpk.security.jsse;import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore;import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;import org.junit.Test;public class SSLSocketTest {@Testpublic void testRunServer() throws Exception {//获取SSL上下文SSLContext context = SSLContext.getInstance("SSL");String keyStorePassword = "password";//获取服务端KeyStoreKeyStore serverKeys = getKeyStore("serverKeys", "jks", keyStorePassword);//获取KeyManagerFactoryKeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());String privateKeyPassword = "password";//初始化KeyManagerFactorykeyManagerFactory.init(serverKeys, privateKeyPassword.toCharArray());//获取TrustManagerFactoryTrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());String trustStorePassword = "password";//获取服务端信任KeyStoreKeyStore serverTrustKeys = getKeyStore("serverTrust", "jks", trustStorePassword);//初始化TrustManagerFactorytrustManagerFactory.init(serverTrustKeys);//初始化SSL上下文context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);//使用SSL上下文获取SSLServerSocketFactorySSLServerSocketFactory ssf = (SSLServerSocketFactory) context.getServerSocketFactory();//使用SSLServerSocketFactory创建出SSLServerSocket,并监听指定端口SSLServerSocket serverSocket = (SSLServerSocket) ssf.createServerSocket(9999);//设置需要对客户端进行认证serverSocket.setNeedClientAuth(true);while(true) {try {//等待客户端连接SSLSocket socket = (SSLSocket) serverSocket.accept();InputStream in = socket.getInputStream();byte[] buf = new byte[1024];int len = in.read(buf);System.out.println(new String(buf, 0, len));in.close();} catch (Exception e) {e.printStackTrace();}}}@Testpublic void testRunClient() throws Exception {SSLContext context = SSLContext.getInstance("SSL");String keyStorePassword = "password";KeyStore clientKeys = SimpleSSLServer.getKeyStore("clientKeys", "jks", keyStorePassword);KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());String privateKeyPassword = "xtayfjpk";keyManagerFactory.init(clientKeys, privateKeyPassword.toCharArray());TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());String trustStorePassword = "password";KeyStore serverTrustKeys = getKeyStore("clientTrust", "jks", trustStorePassword);trustManagerFactory.init(serverTrustKeys);context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);//使用SSL上下文创建SSLSocketSSLSocketFactory factory = (SSLSocketFactory) context.getSocketFactory();String host = "127.0.0.1";//创建SSLSocketSSLSocket socket = (SSLSocket) factory.createSocket(host, 9999);//与服务端进行通信OutputStream outputStream = socket.getOutputStream();outputStream.write("xtayfjpk".getBytes());outputStream.flush();outputStream.close();socket.close();}public static KeyStore getKeyStore(String keyStorePath, String type, String keyStorePassword) throws Exception {KeyStore keyStore = KeyStore.getInstance(type);FileInputStream in = new FileInputStream(keyStorePath);keyStore.load(in, keyStorePassword.toCharArray());in.close();return keyStore;}
}


能过上面的例子能够发现,这和Tomcat的https协议的配置是一致的,因为Tomcat底层肯定也是使用SSLSocket来实现https协议的。SSLServerSocketFactory还有个getDefault方法直接返回一个SSLServerSocketFactory实例,如果使用此方法不需要创建与初始化SSLContext,有关SSL相关的配置设置在系统属性中,设置系统属性的方式有两种:一是在虚拟机启动的时候设置,如下所示:
-Djavax.net.ssl.keyStore=clientKeys
-Djavax.net.ssl.keyStorePassword=password
-Djavax.net.ssl.trustStore=clientTrust
-Djavax.net.ssl.trustStorePassword=password
二是通过System.setProperty设置。

三、HttpsURLConnection的使用

package com.xtayfjpk.security.jsse;import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyStore;import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;import org.junit.Test;public class HttpsUrlConnectionTest {@Testpublic void test() throws Exception {URL url = new URL("https://localhost:8443/");HttpsURLConnection connection = HttpsURLConnection.class.cast(url.openConnection());SSLContext context = SSLContext.getInstance("SSL");String keyStorePassword = "gitblit";KeyStore clientKeys = SimpleSSLServer.getKeyStore("D:\\java-app\\apache-tomcat-6.0.35\\conf\\clientKeyStore.p12", "pkcs12", keyStorePassword);KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());String privateKeyPassword = "gitblit";keyManagerFactory.init(clientKeys, privateKeyPassword.toCharArray());TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());String trustStorePassword = "gitblit";KeyStore serverTrustKeys = getKeyStore("D:\\java-app\\apache-tomcat-6.0.35\\conf\\clientTrustStore.jks", "jks", trustStorePassword);trustManagerFactory.init(serverTrustKeys);context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);//使用SSL上下文创建SSLSocketSSLSocketFactory factory = (SSLSocketFactory) context.getSocketFactory();//如果服务端没设置需要认证客户端的话,可以不用设置SSLSocketFactoryconnection.setSSLSocketFactory(factory);connection.setDoInput(true);connection.setDoOutput(true);InputStream in = connection.getInputStream();String line = null;BufferedReader reader = new BufferedReader(new InputStreamReader(in));while((line=reader.readLine())!=null) {System.out.println(line);}}public static KeyStore getKeyStore(String keyStorePath, String type, String keyStorePassword) throws Exception {KeyStore keyStore = KeyStore.getInstance(type);FileInputStream in = new FileInputStream(keyStorePath);keyStore.load(in, keyStorePassword.toCharArray());in.close();return keyStore;}
}


四、使服务端KeyStore支持多条目,并可指定被使用条目别名

在Tomcat中HTTPS协议的配置时说到,服务器KeyStore最好只有一个条目,否则会造成所使用条目不确定的情况。但有时候你可能会想,该KeyStore中存储多个条目,在启动时通过配置条目别名来指定具体的条目,因为Tomcat中没有提供别名配置支持,所以KeyStore中最好还是只有一个条目。但如果是自己写SSLSocket程序,可能通过扩展来支持,如下:

package com.xtayfjpk.security;import java.net.Socket;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;public class MyAliasedX509ExtendKeyManager extends X509ExtendedKeyManager {private String keyAlias;private X509KeyManager keyManager;public MyAliasedX509ExtendKeyManager(String keyAlias, X509KeyManager keyManager) {this.keyAlias = keyAlias;this.keyManager = keyManager;}//提供给客户端使用,用于选择客户端Keystore中的一个别名@Overridepublic String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) {String alias = keyAlias==null ? keyManager.chooseClientAlias(keyTypes, issuers, socket) : keyAlias;return alias;}//提供给服务端使用,用于选择服务端Keystore中的一个别名@Overridepublic String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {String alias =  keyAlias==null ? keyManager.chooseServerAlias(keyType, issuers, socket) : keyAlias;return alias;}@Overridepublic X509Certificate[] getCertificateChain(String alias) {return keyManager.getCertificateChain(alias);}@Overridepublic String[] getClientAliases(String keyType, Principal[] issuers) {return keyManager.getClientAliases(keyType, issuers);}@Overridepublic PrivateKey getPrivateKey(String alias) {return keyManager.getPrivateKey(alias);}@Overridepublic String[] getServerAliases(String keyType, Principal[] issuers) {return keyManager.getServerAliases(keyType, issuers);}@Overridepublic String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {String alias =  keyAlias==null ? super.chooseEngineClientAlias(keyType, issuers, engine) : keyAlias;return alias;}@Overridepublic String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) {String alias =  keyAlias==null ? super.chooseEngineServerAlias(keyType, issuers, engine) : keyAlias;return alias;}
}

通过继承X509ExtendedKeyManager,自己实现一个KeyManager,别名通过构造方法传入,然后使用自己的KeyManager实现类包装KeyManagerFactory创建的KeyManager即可通过别名达到指定KeyStore中被使用条目的目的。

-------------------------------- END -------------------------------

及时获取更多精彩文章,请扫码关注如下公众号《云原生之家》:


http://chatgpt.dhexx.cn/article/QjF0xOUO.shtml

相关文章

【ssl认证、证书】java中的ssl语法API说明(SSLContext)、与keytool 工具的联系

文章目录 1. 前言java中的ssl语法与keytool 工具的联系 2. SSLContext的体系2.1 KeyStore2.1.1 通过证书库文件创建&#xff1a;2.1.2 随机生成自签名证书库 2.2 KeyManager2.2.1 KeyManagerFactory工厂创建&#xff1a;2.2.2 自己创建一个密钥管理器数组&#xff1a; 2.3 Trus…

import sslssl._create_default_https_context = ssl._create_unverified_context

# 全局取消证书验证import ssl ssl._create_default_https_context ssl._create_unverified_context参考&#xff1a;urllib.error.URLError: urlopen error [SSL: CERTIFICATE_VERIFY_FAILED]_彭世瑜的博客-CSDN博客报错urllib.error.URLError: <urlopen error [SSL: CERT…

HttpClient配置SSL绕过https证书

HttpClient简介 HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了&#xff0c;越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能&#xff0c;但是对于大部分应用程序来说&#xff0…

java SSLContext

1. 什么是SSLSocket JDK文档指出&#xff0c;SSLSocket扩展Socket并提供使用SSL或TLS协议的安全套接字。 这种套接字是正常的流套接字&#xff0c;但是它们在基础网络传输协议(如TCP)上添加了安全保护层。 具体安全方面的讨论见下一篇。本篇重点关注SSLSocket及相关几个类的使用…

SSLContext

1. 什么是SSLSocket JDK文档指出&#xff0c;SSLSocket扩展Socket并提供使用SSL或TLS协议的安全套接字。 这种套接字是正常的流套接字&#xff0c;但是它们在基础网络传输协议(如TCP)上添加了安全保护层。 具体安全方面的讨论见下一篇。本篇重点关注SSLSocket及相关几个类的使用…

Java SSLSocket的使用

1. 什么是SSLSocket JDK文档指出&#xff0c;SSLSocket扩展Socket并提供使用SSL或TLS协议的安全套接字。 这种套接字是正常的流套接字&#xff0c;但是它们在基础网络传输协议(如TCP)上添加了安全保护层。 具体安全方面的讨论见下一篇。本篇重点关注SSLSocket及相关几个类的…

java网络学习之 JSSE 介绍 包含sslcontext(15)

java 安全套接字扩展 是 在原有的socket之上 封装了一层SSL/TLS 这样的高级网络协议的实现,使得原有的socket 通讯变得安全。 1 SSL/TLS 协议介绍&#xff1a; SSL 是洋文“Secure Sockets Layer”的缩写&#xff0c;中文叫做“安全套接层”。为啥要发明 SSL 这个协议捏&…

java SSLContext创建

概述 HTTPS相对于HTTP多了SSL&#xff08;security sock layer&#xff09;&#xff0c;应用层将数据丢给TCP时&#xff0c;需要经过SSL层的加密处理&#xff1b;TCP层的数据丢给应用层时&#xff0c;需要经过SSL层的解密处理。因此网络中传输的都是加密后的数据&#xff0c;提…

【Jetpack】使用 Room Migration 升级数据库并导出 Schema 文件 ( Schema 文件简介 | 生成 Schema 文件配置 | 生成 Schema 文件过程 )

文章目录 一、Schema 文件简介二、生成 Schema 文件配置三、生成 Schema 文件过程1、数据库版本 1 - 首次运行应用2、数据库版本 1 升级至 数据库版本 2 - 第二次运行应用3、数据库版本 2 升级至 数据库版本 3 - 第三次运行应用 一、Schema 文件简介 使用 Room Migration 升级数…

数据库,schema,catalog三者的涵义(简单描述)

你是否经常见到schema&#xff0c;catalog这些单词&#xff0c;在数据库的背景下是什么意思呢&#xff1f; 两篇参考&#xff1a;http://www.iteye.com/problems/9738 及 http://luckybat.iteye.com/blog/259976 taopian (高级程序员) 2009-01-07 写道 schema是对一个数据库的结…

mysql中information_schema数据库

目录 1、information_schema说明 2、information_schema下的表 2.1 schemata表 2.2 tables表 2.3 columns表 2.4 statistics表 2.5、user_privileges表&#xff08;用户权限表&#xff09; 2.7 table_privileges表&#xff08;表权限表&#xff09; 2.8 column_privileges…

数据库中Schema和Database有什么区别

本文源自&#xff1a; 数据库中Schema和Database有什么区别 - 人生似烟的日志 - 网易博客 http://blog.163.com/baibai_zheng/blog/static/51980755201022125325689/ ------------------------------------------------------------------------------------------------------…

数据库的 Schema 变更实现

一、减少元数据变更的措施 元数据变更是数据库管理中不可避免的工作项&#xff0c;减少元数据变更次数可降低数据库维护和管理成本&#xff0c;减轻对业务的影响。这里我们可以优先考虑以下 3 点&#xff1a; 精细计划 在数据库设计和开发阶段&#xff0c;精细设计元数据结构…

数据库中的 Schema 变更实现

线上沙龙-技术流第 30 期营业啦 05月09日&#xff08;周二&#xff09;19:30 KaiwuDB - B站直播间 传统数据库操作 Schema 变更时&#xff0c;第一步便是锁表&#xff0c;需持续到 Schema 变更操作完成。这样的做法虽然实现简单&#xff0c;无需考虑事务并发带来的影响&#…

SQL SERVER 中的Schema详解

以往 SQL Server 内的对象命名是“服务器.数据库.用户名.对象”&#xff0c;但新版的对象命名改为“服务器.数据库.Schema.对象”。这让你规划数据库对象命名时更有弹性。 架构是形成单个命名空间的数据库实体的集合。命名空间是一个集合&#xff0c;其中每个元素的名称都是唯…

Schema是什么

数据库中的Schema 在SQL环境下&#xff0c;schema就是数据库对象的集合&#xff0c; 所谓的数据库对象也就是常说的表&#xff0c;索引&#xff0c;视图&#xff0c;存储过程等。 所谓的数据库对象也就是常说的表&#xff0c;索引&#xff0c;视图&#xff0c;存储过程等。 所…

如何理解MYSQL中schema的概念

学习ES中用到了mapping&#xff0c;百度说类似与MYSQL中的schema&#xff0c;于是对schema的概念很模糊&#xff0c;这里做一下笔记&#xff0c;进行学习。 schema 读音&#xff1a; /ˈskiːmə/ &#xff0c;汉语意思&#xff1a;&#xff08;计划或理论的&#xff09;提要&a…

MySQL的Schema是什么?

1 Schema概念 schema在数据库中表示的是数据库对象集合&#xff0c;它包含了各种对像&#xff0c;比如&#xff1a;表&#xff0c;视图&#xff0c;存储过程&#xff0c;索引等等。 一般一个用户对应一个集合&#xff0c;所以为区分不同集合就需给不同集合起名。用户的schema名…

【database】数据库schema概念解读

schema概念定义 数据库中的schema有多种不同含义和实现&#xff1a; 数据库中的数据模型(data model)数据库中的整个数据结构(data structure)和程序(program)命名空间(namespace)是SQL的一个元素 1. Data Model 数据库schema的含义之一是数据库中表之间的结构&#xff0c;…

SQL Server: 数据库模式SCHEMA

在SQLServer等关系数据库管理系统(RDBMS)中&#xff0c;数据库包含各种对象。 在数据库中&#xff0c;模式(SCHEMA)是指数据库对象的逻辑集合。可以根据应用程序、访问权限和安全性使用模式(SCHEMA)来對对象分組。 SQL Server schemas SQL Server提供以下内置逻辑模式&#…