【加密与解密】【07】SSL安全套件全解析

SSL/TLS协议

SSL,Secure Socket Layer,安全套接层

TLS,Transport Layer Security,传输层安全协议

TLS是SSL的最终完善版本,一般也可称为SSL协议

SSL是负责传输层安全,确定传输层数据如何封装的一套协议

SSL协议阶段
  • 算法协商
  • 数字证书验证
  • 数据通信
SSL协议核心内容
  • 事先准备:

  • 服务端生成自己的私钥和公钥

  • 服务端向CA机构申请SSL证书

  • CA向服务器颁发数字证书,该证书通过CA私钥加密,包含了服务端域名和公钥,用于证明服务端身份

  • 算法协商阶段:

  • 客户端和服务端分别生成随机数RNC和RNS,连同SSL算法参数一起发送给对方

  • 数字证书验证阶段:

  • 服务端将自己的数据进行摘要,再通过私钥加密,生成数字签名

  • 服务端将数据+数字签名+数字证书,一同发往客户端

  • 客户端通过CA公钥解密数字证书,确认证书与域名一致后,拿到服务端公钥(保证了公钥未被篡改)

  • 客户端通过服务端公钥解开数字签名,得到数据摘要(保证了数据来自服务端)

  • 客户端对数据部分进行摘要,与数字签名中的摘要进行对比(保证了数据完整性)

  • 客户端生成随机数PMS(Pre Master Secret),通过服务端公钥加密,发给服务端

  • 服务端通过私钥解密出PMS

  • 双方根据RNC+RNS+PMS构建主密钥MS(Master Secret),完成对称秘钥协商

  • 数据通信阶段:

  • 服务端和客户端通过主密钥MS,加密解密通信数据

  • 双向认证:

  • 如果服务端也要求客户端持有SSL证书,则增加一步服务端验证客户端证书的过程

  • 秘钥协商算法:

  • 以上流程使用的是DH秘钥协商算法

  • 如果用的是RSA算法,则直接将PMS作为MS使用,并且由客户端发送给服务端

SSL协议应用
  • 最常见的是应用于Https协议
  • 此外也可应用于Socket和WebSocket
SSL核心类
  • KeyManager,用于管理自己的私钥和证书,多用于服务端
  • TrustManager,用于验证收到的证书是否可信,多用于客户端
  • 服务端也可以要求客户端也发送安全证书,即双向认证,此时双方都要同时设置KeyManager+TrustManager
  • KeyStore,秘钥仓库,用来存储私钥、公钥、证书等数据,可设置密码
  • TrustStore,KeyStore的一种,存储CA证书,用于验证服务端身份正确性,密码公开
  • KeyStore和TrustStore的区别,仅在于存储的内容不同,它们可以是同一个文件,但是不建议这么做
  • Java中比较常见的KeyStore文件格式是JKS,此外还有CRT、PEM、P12、KEY等格式,私钥和证书也可能分开保存
  • KeyManagerFactory,用于创建KeyManager,一般通过algorithm和keystore文件来初始化
  • TrustManagerFactory,用于创建TrustManager,一般通过algorithm和keystore文件来初始化
  • SSLContext,用于整体管理SSL相关事务,一般通过KeyManager和TrustManager来初始化
  • 当KeyManager和TrustManager未指定时,SSLContext会从系统已安装的SecurityProvider中,搜索合适的Provider来处理对应工作
  • SSLServerSocketFactory,用于创建带SSL功能的ServerSocket,可通过SSLContext创建
  • SSLSocketFactory,用于创建带SSL功能的ClientSocket,可通过SSLContext创建
  • 也可以不使用Factory和KeyStore,通过自定义的方式来创建KeyManager和TrustManager
  • SSLSessionContext,维护所有会话信息,可通过SSLContext.getSessionContext获得
  • SSLSession,可通过SSLSessionContext或SSLSocket来获得
  • SSLServerSocket可以接收来自多个客户端的连接,SSLSocket只能连接指定的服务器和端口
  • SSLEngine,用于实现SSL握手,通过SSLContext创建,一般不用自己去实现,属于偏内部的Class
通过KeyTool生成KeyStore

学习SSL首先得有用于测试的SSL证书库,所以我们先来看看如何生成KeyStore

private.keystore和public.truststore本质上都是JKS文件,只是为了区分作用而换了后缀

# 生成私钥证书,首个名称请输入域名或ip
keytool -genkeypair -alias alias -keyalg RSA -validity 365 -keystore private.keystore# 生成公钥证书
keytool -export -alias alias -keystore private.keystore -rfc -file public.cer# 公钥证书转为JKS格式
keytool -import -alias alias -file public.cer -keystore public.truststore
KeyStore格式转换

JKS是Java专用的秘钥仓库格式

不同平台和语言的对KeyStore的支持性和使用习惯并不一样

比如安卓就不支持JKS格式,安卓上的证书一般使用P12格式

我们可以通过KeyStore Explorer软件来转换

https://keystore-explorer.org/downloads.html
使用带SSL的TcpSocket
import java.io.*
import java.security.KeyStore
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLServerSocket
import javax.net.ssl.SSLSocket
import javax.net.ssl.TrustManagerFactoryconst val serverKeyStore = "resources/private.keystore"
const val clientKeyStore = "resources/public.truststore"
const val passphrase = "123456"const val serverPort = 18001fun main() {Thread(::launchServerSocket).start()Thread.sleep(500)Thread(::launchClientSocket).start()
}fun launchServerSocket() {// load key manager from key storeval keyManagerFactory = KeyManagerFactory.getInstance("SunX509")val keyStore = KeyStore.getInstance("JKS")keyStore.load(FileInputStream(serverKeyStore), passphrase.toCharArray())keyManagerFactory.init(keyStore, passphrase.toCharArray())val keyManagers = keyManagerFactory.keyManagers// init ssl contextval context = SSLContext.getInstance("TLS")context.init(keyManagers, null, null)// create server socketval serverSocketFactory = context.serverSocketFactoryval serverSocket = serverSocketFactory.createServerSocket(serverPort) as SSLServerSocketserverSocket.needClientAuth = false// accept client sessionval socket = serverSocket.accept() as SSLSocket// communication with clientwhile (true) {Thread.sleep(500)socket.getOutputStream().write("Hello World".encodeToByteArray())socket.getOutputStream().flush()}
}fun launchClientSocket() {// load trust manager from trust storeval trustManagerFactory = TrustManagerFactory.getInstance("SunX509")val trustStore = KeyStore.getInstance("JKS")trustStore.load(FileInputStream(clientKeyStore), passphrase.toCharArray())trustManagerFactory.init(trustStore)val trustManagers = trustManagerFactory.trustManagers// init ssl contextval context = SSLContext.getInstance("TLS")context.init(null, trustManagers, null)// create client socket and auto connectval sslSocketFactory = context.socketFactoryval socket = sslSocketFactory.createSocket("localhost", serverPort) as SSLSocket// communication with serverval buffer = ByteArray(1024)while (true) {val len = socket.getInputStream().read(buffer)if (len > 0) {val message = String(buffer, 0, len)println("Client Received: $message")}}
}
使用带SSL的HttpServer

大多网络编程框架,都是默认支持Https协议的,但仅限于由CA机构颁发的可信任证书

对于人工签发,未经CA机构授权的自签名证书,必须由开发者自己去实现验证逻辑

import com.sun.net.httpserver.HttpsConfigurator
import com.sun.net.httpserver.HttpsServer
import java.io.*
import java.net.InetSocketAddress
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import java.security.KeyStore
import java.util.*
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactoryconst val serverKeyStore = "resources/private.keystore"
const val clientKeyStore = "resources/public.truststore"
const val passphrase = "123456"const val serverPort = 18001fun main() {Thread(::launchHttpServer).start()Thread.sleep(1500)Thread(::launchHttpClient).start()
}fun launchHttpServer() {// load key manager from key storeval keyManagerFactory = KeyManagerFactory.getInstance("SunX509")val keyStore = KeyStore.getInstance("JKS")keyStore.load(FileInputStream(serverKeyStore), passphrase.toCharArray())keyManagerFactory.init(keyStore, passphrase.toCharArray())val keyManagers = keyManagerFactory.keyManagers// configure ssl contextval context = SSLContext.getInstance("TLS")context.init(keyManagers, null, null)// create https serverval server = HttpsServer.create(InetSocketAddress(serverPort), 10)// configure httpsval configurator = HttpsConfigurator(context)server.httpsConfigurator = configurator// create serviceserver.createContext("/home") { exchange ->val response = Date().toString().encodeToByteArray()exchange.sendResponseHeaders(200, response.size.toLong())exchange.responseBody.write(response)exchange.responseBody.close()}// start https serverserver.start()
}fun launchHttpClient() {// load trust manager from trust storeval trustManagerFactory = TrustManagerFactory.getInstance("SunX509")val trustStore = KeyStore.getInstance("JKS")trustStore.load(FileInputStream(clientKeyStore), passphrase.toCharArray())trustManagerFactory.init(trustStore)val trustManagers = trustManagerFactory.trustManagers// init ssl contextval context = SSLContext.getInstance("TLS")context.init(null, trustManagers, null)// create http clientval uri = URI.create("https://localhost:18001/home")val client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).sslContext(context).build()// send requestval request = HttpRequest.newBuilder().GET().uri(uri).build()// get responseval response = client.send(request, HttpResponse.BodyHandlers.ofString())println(response.body())
}
使用带SSL的WebSocket

这里我们使用比较出名的Java-WebSocket库来实现WebSocket服务端和客户端功能

api("org.java-websocket:Java-WebSocket:1.5.1")

为WebSocketServer设置SSL

fun setServerSSL(server: WebSocketServer) {// load key manager from key storeval keyManagerFactory = KeyManagerFactory.getInstance("SunX509")val keyStore = KeyStore.getInstance("JKS")keyStore.load(FileInputStream(serverKeyStore), passphrase.toCharArray())keyManagerFactory.init(keyStore, passphrase.toCharArray())val keyManagers = keyManagerFactory.keyManagers// configure ssl contextval context = SSLContext.getInstance("TLS")context.init(keyManagers, null, null)// configure server sslval websocketServerFactory = DefaultSSLWebSocketServerFactory(context)server.setWebSocketFactory(websocketServerFactory)
}

为WebSocketClient设置SSL

fun setClientSSL(client: WebSocketClient) {// load trust manager from trust storeval trustManagerFactory = TrustManagerFactory.getInstance("SunX509")val trustStore = KeyStore.getInstance("JKS")trustStore.load(FileInputStream(clientKeyStore), passphrase.toCharArray())trustManagerFactory.init(trustStore)val trustManagers = trustManagerFactory.trustManagers// configure ssl contextval context = SSLContext.getInstance("TLS")context.init(null, trustManagers, null)// configure client sslval sslSocketFactory = context.socketFactoryclient.setSocketFactory(sslSocketFactory)
}
在OkHttp中自定义KeyManager和TrustManager

以上案例,都是通过KeyStore来实现KeyManager和TrustManager的管理功能

现在我们不用KeyStore,通过自定义规则,来实现秘钥管理和证书验证功能

我们以OkHttp框架为例

import okhttp3.OkHttpClient
import java.security.cert.X509Certificate
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSession
import javax.net.ssl.X509TrustManagerfun setOkHttpSSL(builder: OkHttpClient.Builder) {val trustManager = object : X509TrustManager {override fun checkClientTrusted(chain: Array<out X509Certificate>, authType: String) {}override fun checkServerTrusted(chain: Array<out X509Certificate>, authType: String) {}override fun getAcceptedIssuers(): Array<X509Certificate> = emptyArray()}val trustManagers = arrayOf(trustManager)val hostnameVerifier = HostnameVerifier { hostname: String, session: SSLSession -> true }val sslContext = SSLContext.getInstance("SSL")sslContext.init(null, trustManagers, null)val socketFactory = sslContext.socketFactorybuilder.sslSocketFactory(socketFactory, trustManager)builder.hostnameVerifier(hostnameVerifier)
}

现在我们用OkHttp来替换上面的HttpClient来访问服务器

fun launchHttpClient() {val url = "https://localhost:18001/home"// create okhttp clientval builder = OkHttpClient.Builder()setOkHttpSSL(builder)val client = builder.build()// create requestval request = Request.Builder().url(url).get().build()// execute callval call = client.newCall(request)val response = call.execute()// print responseval responseBody = response.body.string()println(responseBody)
}

这里我们为了演示,不让问题复杂化,只是简单地信任了所有的证书,并不能起到实际的安全作用

关于KeyManager,TrustManager,HostnameVerifier的正式用法,可以参考以下类的源码

SunX509KeyManagerImpl X509TrustManagerImpl OkHostnameVerifier

SSL证书格式
  • JKS,二进制格式存储,Java专属格式

    一般为私钥+证书+密码,或只有公钥的组合

    常用于Tomcat服务器

  • PEM,文本格式存储

    可保存私钥和证书,一般以BEGIN开头,END结尾,中间为BASE64编码字符串

    常用于Apache或Nginx服务器

  • CER/DER,二进制格式存储

    只能保存证书

    常用于Windows服务器

  • CRT,只是一个后缀名,可以是PEM编码,也可以是CER编码

    一般只用来保存证书,不存储私钥

    可以将私钥单独保存,以KEY作为后缀,来区分秘钥文件和证书文件

    KEY文件可以是PEM编码,也可以是CER编码

  • P12/PKCS12/PFX,二进制格式存储

    一般同时包含私钥和证书,有密码保护

    常用于Windows IIS服务器

  • CSR,证书请求文件

    这个不是证书,而是通过私钥向CA申请公钥的请求文件

  • 最后,要注意的是,文件后缀和证书格式之间没有必然关系,还是以文件内容的实际存储格式为准

SSL证书转换工具
  • OpenSSL
  • KeyTool
  • KeyStore Explorer
OpenSSL指令
  • genrsa,生成秘钥
  • req,创建自签名根证书,或生成证书请求文件
  • x509,查看,创建,或转换证书
  • -in,输入文件
  • -out,输出文件
  • -inform,输入文件格式
  • -outform,输出文件格式
  • -CA,指定根证书
  • -CAkey,指定根证书私钥
  • -CAserial,指定CA证书
  • -CAcreateserial,创建下级CA证书
OpenSSL制作证书
# 创建根证书
openssl req -new -x509 -days 365 -extensions v3_ca -keyout crt/ca.key -out crt/ca.crt# 颁发服务端证书
openssl genrsa -out crt/server.key 2048
openssl req -out crt/server.csr -key crt/server.key -new
openssl x509 -req -in crt/server.csr -CA crt/ca.crt -CAkey crt/ca.key -CAcreateserial -out crt/server.crt -days 365# 颁发客户端证书
openssl genrsa -out crt/client.key 2048
openssl req -out crt/client.csr -key crt/client.key -new
openssl x509 -req -in crt/client.csr -CA crt/ca.crt -CAkey crt/ca.key -CAcreateserial -out crt/client.crt -days 365# 查看服务端证书
openssl x509 -in crt/server.crt -text -noout
End

到此为止,基本涵盖了Java SSL的所有核心内容,已经足以满足大家日常开发需要

更高阶的用法,可能在专业的领域才能用得到,希望大家遇到时,能勇于自己去研究!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/864041.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

讨论Nginx服务器的反爬虫和反DDoS攻击策略

Nginx服务器是一个高性能的Web服务器和反向代理服务器&#xff0c;具有强大的反爬虫和反DDoS攻击能力。本文将讨论Nginx服务器的反爬虫和反DDoS攻击策略&#xff0c;并给出相关的代码示例。 一、反爬虫策略 爬虫是一种自动化程序&#xff0c;用于从互联网上收集特定网站的数据…

Java 内存分页

1. 查询出要分页的总数 2. 根据 stream 流进行分页 3. 当分页数超过总数&#xff0c;返回空集合。例&#xff1a;总数10&#xff0c;页码2&#xff0c;pagesize10 4. 当最后一页不够 pageSize, limit(pageSize) 返回实际条数 例&#xff1a;12条数据&#xff0c;pageSize10…

使用Petalinux设计linux系统

文章目录 1.通过 Vivado 创建硬件平台&#xff0c;得到 hdf 硬件描述文件2.设置 Petalinux 环境变量3.创建 Petalinux 工程4.配置Petalinux 工程5.配置Linux内核6.配置Linux根文件系统7.配置设备树文件8.编译 Petalinux 工程9.制作BOOT.BIN启动文件10.制作SD启动卡 1.通过 Viva…

GaussDB关键技术原理:高性能(三)

GaussDB关键技术原理&#xff1a;高性能&#xff08;二&#xff09;从查询处理综述对GaussDB的高性能技术进行了解读&#xff0c;本篇将从查询重写RBO、物理优化CBO、分布式优化器、布式执行框架、轻量全局事务管理GTM-lite等五方面对高性能关键技术进行分享。 目录 3 高性能…

Jupyter Notebook相关

Jupyter Notebook 相关 一、什么是 Jupyter Notebook&#xff1f; 1.1 基本概念 Jupyter Notebook 是一个基于 web 的应用程序&#xff0c;可以用来创建和共享包含代码、文本、公式、图像和图表的文档。它类似于一个电子笔记本&#xff0c;你可以在一个页面上写代码并立即运行…

.secret勒索病毒详解,如何防御网络隐秘威胁

引言&#xff1a; 在数字化日益普及的今天&#xff0c;网络安全问题愈发凸显&#xff0c;其中勒索病毒作为一种极具破坏性的恶意软件&#xff0c;给个人用户和企业带来了巨大的损失和心理压力。.secret勒索病毒&#xff0c;作为这一威胁中的佼佼者&#xff0c;以其高度的隐蔽性…

Android Graphics 显示系统 - BufferQueue的状态监测

“ BufferQueue作为连接生产者和消费者的桥梁&#xff0c;时刻掌握队列中每一块Buffer的状态&#xff0c;对于解决一些卡死卡顿问题很有帮助&#xff0c;辨别是否有生产者或消费者长期持有大量Buffer不放导致运行不畅的情况。” 01 — 前言 在Android系统中&#xff0c;应用U…

Redis基础教程(四):redis键(key)

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

多层感知机与CLIP在推荐系统和多模态学习中的应用

MLP多层感知机 在推荐系统中,MLP(Multi-Layer Perceptron,多层感知机)是一种常用的神经网络模型,用于捕捉用户和物品之间的复杂非线性关系,从而生成高质量的推荐结果。以下是 MLP 在推荐系统中的应用及其优势。 MLP 在推荐系统中的作用 用户和物品特征的表示: MLP 能够…

Spring Boot应用的部署与扩展

Spring Boot应用的部署与扩展 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 引言 Spring Boot作为现代化Java应用的首选框架之一&#xff0c;以其简化的配置…

MicroBin好用的粘贴板工具

有时候你可能想从一台电脑上粘贴文本到另一台电脑上&#xff0c;或者是你想要分享一张图片或者是一些文件&#xff0c;某些设备上登陆qq和微信有不太方便&#xff0c;那么就可以使用MicroBin&#xff0c;它不但可以实现跨设备复制粘贴的功能&#xff0c;还支持文件上传等功能 …

微信小程序的在线客服系统源码 附带完整的源代码包以及搭建部署教程

系统概述 微信小程序的在线客服系统源码是一套专门为微信小程序开发的客服解决方案。它通过与微信小程序的紧密集成&#xff0c;为用户提供了便捷、高效的客服沟通渠道。该系统源码采用先进的技术架构&#xff0c;具备良好的稳定性和扩展性&#xff0c;能够满足不同规模企业的…

大数据开发语言 Scala(二):变量和数据类型

目录 1. 变量的基本概念 1.1 不可变变量&#xff08;val&#xff09; 1.2 可变变量&#xff08;var&#xff09; 2. 数据类型详解 2.1 基本数据类型 2.1.1 数字类型 2.1.2 字符类型 2.1.3 布尔类型 2.2 复杂数据类型 2.2.1 数组 2.2.2 元组 2.2.3 列表 2.2.4 集合…

韩顺平0基础学java——第34天

p675-689 UDP网络编程 1.类 DatagramSocket和 DatagramPacket[数据包/数据报]实现了基于UDP协议网络程序。 2.UDP数据报通过数据报套接字DatagramSocket发送和接收&#xff0c;系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。 3.DatagramPacket对象…

【前端】从零开始学习编写HTML

目录 一、什么是前端 二、什么是HTML 三、HTML文件的基本结构 四、HTML常见标签 4.1 注释标签 4.2 标题标签 4.3 段落标签 4.4 换行标签 4.5 格式化标签 4.6 图片标签 4.7 超链接标签 4.8 表格标签 4.9 列表标签 4.10 表单标签 &#xff08;1&#xff09;form标…

Python 学习之面向对象(四)

面向对象编程&#xff08;Object-Oriented Programming, OOP&#xff09;是一种编程范式&#xff0c;它使用“对象”来设计应用程序和软件系统。在Python中&#xff0c;面向对象编程是一个核心概念&#xff0c;并得到了广泛的支持。 以下是Python面向对象编程的一些基本概念和特…

MySQL高可用(MHA高可用)

什么是 MHA MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。 MHA 的出现就是解决MySQL 单点的问题。 MySQL故障切换过程中&#xff0c;MHA能做到0-30秒内自动完成故障切换操作。 MHA能在故障切换的过程中最大…

内容营销专家刘鑫炜:如何撰写一篇吸睛又能转化的医疗推广软文?

在我每天要处理的稿件中&#xff0c;有1/3以上是医疗软文&#xff0c;但稿件质量情况不容乐观&#xff0c;大部分医疗软文甚至用极其糟糕来形容都为过&#xff0c;互联网都到下半场了&#xff0c;很多医疗机构营销人员的营销思维还是停留在二十几年前&#xff0c;投放的软文还是…

SpringMVC系列八: 手动实现SpringMVC底层机制-第三阶段

手动实现SpringMVC底层机制 实现任务阶段六&#x1f34d;完成控制器方法获取参数-RequestParam1.&#x1f966;将 方法的 HttpServletRequest 和 HttpServletResponse 参数封装到数组, 进行反射调用2.&#x1f966;在方法形参处, 指定 RequestParam, 将对应的实参封装到参数数组…

Perl正则表达式捕获组:深入探索与实战应用

&#x1f575;️‍♂️ Perl正则表达式捕获组&#xff1a;深入探索与实战应用 在Perl的世界里&#xff0c;正则表达式是其强大的文本处理能力的基石。捕获组作为正则表达式中的一个核心概念&#xff0c;允许我们从匹配的文本中提取子字符串。本文将深入探讨如何在Perl中使用正…