Ubuntu 下 nginx-1.24.0 源码分析 - ngx_ssl_init 函数
#if (NGX_OPENSSL)ngx_ssl_init(log); #endif
objs/ngx_auto_config.h 中
#ifndef NGX_OPENSSL #define NGX_OPENSSL 1 #endif
所以这个条件编译成立
NGX_OPENSSL
是一个宏定义,用于控制与 OpenSSL 相关的功能是否被启用若用户通过
./configure
参数(如--with-http_ssl_module
)显式启用SSL模块,则NGX_OPENSSL
宏会被定义OpenSSL 是一个开源的加密库,广泛用于实现安全通信协议(如 HTTPS、TLS/SSL)以及提供各种加密和解密功能
ngx_ssl_init
声明
在 src/event/ngx_event_openssl.h 中:
ngx_int_t ngx_ssl_init(ngx_log_t *log);
实现
在 src\event\ngx_event_openssl.c 中:
ngx_int_t ngx_ssl_init(ngx_log_t *log) { #if OPENSSL_VERSION_NUMBER >= 0x10100003Lif (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed");return NGX_ERROR;}/** OPENSSL_init_ssl() may leave errors in the error queue* while returning success*/ERR_clear_error();#elseOPENSSL_config(NULL);SSL_library_init();SSL_load_error_strings();OpenSSL_add_all_algorithms();#endif#ifndef SSL_OP_NO_COMPRESSION{/** Disable gzip compression in OpenSSL prior to 1.0.0 version,* this saves about 522K per connection.*/int n;STACK_OF(SSL_COMP) *ssl_comp_methods;ssl_comp_methods = SSL_COMP_get_compression_methods();n = sk_SSL_COMP_num(ssl_comp_methods);while (n--) {(void) sk_SSL_COMP_pop(ssl_comp_methods);}} #endifngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);if (ngx_ssl_connection_index == -1) {ngx_ssl_error(NGX_LOG_ALERT, log, 0, "SSL_get_ex_new_index() failed");return NGX_ERROR;}ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,NULL);if (ngx_ssl_server_conf_index == -1) {ngx_ssl_error(NGX_LOG_ALERT, log, 0,"SSL_CTX_get_ex_new_index() failed");return NGX_ERROR;}ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,NULL);if (ngx_ssl_session_cache_index == -1) {ngx_ssl_error(NGX_LOG_ALERT, log, 0,"SSL_CTX_get_ex_new_index() failed");return NGX_ERROR;}ngx_ssl_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,NULL);if (ngx_ssl_ticket_keys_index == -1) {ngx_ssl_error(NGX_LOG_ALERT, log, 0,"SSL_CTX_get_ex_new_index() failed");return NGX_ERROR;}ngx_ssl_ocsp_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);if (ngx_ssl_ocsp_index == -1) {ngx_ssl_error(NGX_LOG_ALERT, log, 0,"SSL_CTX_get_ex_new_index() failed");return NGX_ERROR;}ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,NULL);if (ngx_ssl_certificate_index == -1) {ngx_ssl_error(NGX_LOG_ALERT, log, 0,"SSL_CTX_get_ex_new_index() failed");return NGX_ERROR;}ngx_ssl_next_certificate_index = X509_get_ex_new_index(0, NULL, NULL, NULL,NULL);if (ngx_ssl_next_certificate_index == -1) {ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");return NGX_ERROR;}ngx_ssl_certificate_name_index = X509_get_ex_new_index(0, NULL, NULL, NULL,NULL);if (ngx_ssl_certificate_name_index == -1) {ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");return NGX_ERROR;}ngx_ssl_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL, NULL);if (ngx_ssl_stapling_index == -1) {ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");return NGX_ERROR;}return NGX_OK; }
这段代码是 Nginx 源码中用于初始化 OpenSSL 库的核心函数
ngx_ssl_init
,其主要目的是为 Nginx 的 SSL/TLS 功能提供必要的初始化操作函数的主要功能
ngx_ssl_init
函数的主要任务是:
- 初始化 OpenSSL 库,确保其能够正常工作。
- 配置 SSL/TLS 相关的全局状态。
- 注册自定义扩展索引(ex_data),以便在后续的 SSL/TLS 上下文中存储和访问 Nginx 特定的数据。
主要逻辑分析
(1) OpenSSL 库的初始化
#if OPENSSL_VERSION_NUMBER >= 0x10100003Lif (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed");return NGX_ERROR;}ERR_clear_error(); #elseOPENSSL_config(NULL);SSL_library_init();SSL_load_error_strings();OpenSSL_add_all_algorithms(); #endif
条件编译 :
- 如果 OpenSSL 版本号大于等于
0x10100003L
(即 OpenSSL 1.1.0 及以上版本),使用OPENSSL_init_ssl
函数进行初始化。- 对于较老的 OpenSSL 版本(低于 1.1.0),则通过一系列传统函数(如
OPENSSL_config
、SSL_library_init
等)进行初始化。
新版本的初始化 :
if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed");return NGX_ERROR; } ERR_clear_error();
- 调用
OPENSSL_init_ssl
初始化 OpenSSL,并加载配置文件。- 即使
OPENSSL_init_ssl
返回成功,也可能在错误队列中留下未处理的错误信息,因此调用ERR_clear_error
清除这些潜在的错误。
旧版本的初始化 :
OPENSSL_config(NULL); SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms();
OPENSSL_config
加载 OpenSSL 配置文件。SSL_library_init
初始化 SSL 库。SSL_load_error_strings
加载错误字符串,方便调试。OpenSSL_add_all_algorithms
注册所有加密算法。
(2) 禁用压缩(针对旧版本 OpenSSL)
#ifndef SSL_OP_NO_COMPRESSION {int n;STACK_OF(SSL_COMP) *ssl_comp_methods;ssl_comp_methods = SSL_COMP_get_compression_methods();n = sk_SSL_COMP_num(ssl_comp_methods);while (n--) {(void) sk_SSL_COMP_pop(ssl_comp_methods);} } #endif
- 在 OpenSSL 1.0.0 之前的版本中,没有
SSL_OP_NO_COMPRESSION
宏来禁用压缩。- 压缩可能导致内存消耗增加(每连接约 522KB),因此手动禁用压缩:
- 获取当前支持的压缩方法列表。
- 遍历并移除所有压缩方法。
(3) 创建扩展索引
Nginx 使用 OpenSSL 的扩展机制来存储自定义数据。以下是创建的几个扩展索引及其用途:
1.连接级别的扩展索引 :
ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
- 用于在 SSL 连接对象中存储 Nginx 的自定义数据。
2.上下文级别的扩展索引 :
ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
用于在 SSL 上下文对象中存储服务器配置信息
3.会话缓存扩展索引 :
ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
- 用于管理 SSL 会话缓存。
4.其他扩展索引 :
ngx_ssl_ticket_keys_index
:用于存储会话票据密钥。
ngx_ssl_ocsp_index
:用于存储 OCSP(在线证书状态协议)相关数据。
ngx_ssl_certificate_index
和ngx_ssl_next_certificate_index
:用于管理证书链。
ngx_ssl_stapling_index
:用于 OCSP Stapling(证书状态绑定)。每个扩展索引的创建都检查返回值是否为
-1
,如果失败则记录错误日志并返回NGX_ERROR
意图
1 兼容性
- 代码通过条件编译兼容了不同版本的 OpenSSL(1.1.0 及以上版本与旧版本)。
- 旧版本中手动禁用压缩的逻辑体现了对性能优化的关注。
2 扩展性
- 使用 OpenSSL 的扩展机制(
SSL_get_ex_new_index
和SSL_CTX_get_ex_new_index
)为 Nginx 提供了灵活的自定义数据存储能力。- 这些扩展索引使得 Nginx 能够在 SSL/TLS 层面上集成更多的功能(如会话缓存、OCSP Stapling 等)。
3 错误处理
- 每个关键步骤都有详细的错误检查和日志记录。
- 例如,
OPENSSL_init_ssl
和SSL_get_ex_new_index
等函数的返回值都被严格验证,确保初始化失败时能够及时发现问题。4 性能优化
- 禁用压缩是为了减少内存消耗,提升性能。
- 通过扩展索引管理自定义数据,避免了全局变量的使用,提高了模块化程度和可维护性。
详解
gcc -E src/event/ngx_event_openssl.c \-I src/core \-I src/event \-I src/event/modules \-I src/os/unix \-I objs \> ngx_event_openssl_preprocessed.c
使用以上命令处理条件编译
在输出文件 ngx_event_openssl_preprocessed.c 中 查找 ngx_ssl_init
ngx_int_t ngx_ssl_init(ngx_log_t *log) {if (OPENSSL_init_ssl( # 148 "src/event/ngx_event_openssl.c" 3 40x00000040L # 148 "src/event/ngx_event_openssl.c", # 148 "src/event/ngx_event_openssl.c" 3 4((void *)0) # 148 "src/event/ngx_event_openssl.c") == 0) {ngx_ssl_error(2, log, 0, "OPENSSL_init_ssl() failed");return -1;}ERR_clear_error(); # 189 "src/event/ngx_event_openssl.c"ngx_ssl_connection_index = # 189 "src/event/ngx_event_openssl.c" 3 4CRYPTO_get_ex_new_index(0, # 189 "src/event/ngx_event_openssl.c"0 # 189 "src/event/ngx_event_openssl.c" 3 4, ((void *)0), ((void *)0), ((void *)0), ((void *)0)) # 189 "src/event/ngx_event_openssl.c";if (ngx_ssl_connection_index == -1) {ngx_ssl_error(2, log, 0, "SSL_get_ex_new_index() failed");return -1;}ngx_ssl_server_conf_index = # 196 "src/event/ngx_event_openssl.c" 3 4CRYPTO_get_ex_new_index(1, # 196 "src/event/ngx_event_openssl.c"0 # 196 "src/event/ngx_event_openssl.c" 3 4, ((void *)0), ((void *)0), ((void *)0), ((void *)0))# 197 "src/event/ngx_event_openssl.c";if (ngx_ssl_server_conf_index == -1) {ngx_ssl_error(2, log, 0,"SSL_CTX_get_ex_new_index() failed");return -1;}ngx_ssl_session_cache_index = # 204 "src/event/ngx_event_openssl.c" 3 4CRYPTO_get_ex_new_index(1, # 204 "src/event/ngx_event_openssl.c"0 # 204 "src/event/ngx_event_openssl.c" 3 4, ((void *)0), ((void *)0), ((void *)0), ((void *)0))# 205 "src/event/ngx_event_openssl.c";if (ngx_ssl_session_cache_index == -1) {ngx_ssl_error(2, log, 0,"SSL_CTX_get_ex_new_index() failed");return -1;}ngx_ssl_ticket_keys_index = # 212 "src/event/ngx_event_openssl.c" 3 4CRYPTO_get_ex_new_index(1, # 212 "src/event/ngx_event_openssl.c"0 # 212 "src/event/ngx_event_openssl.c" 3 4, ((void *)0), ((void *)0), ((void *)0), ((void *)0))# 213 "src/event/ngx_event_openssl.c";if (ngx_ssl_ticket_keys_index == -1) {ngx_ssl_error(2, log, 0,"SSL_CTX_get_ex_new_index() failed");return -1;}ngx_ssl_ocsp_index = # 220 "src/event/ngx_event_openssl.c" 3 4CRYPTO_get_ex_new_index(1, # 220 "src/event/ngx_event_openssl.c"0 # 220 "src/event/ngx_event_openssl.c" 3 4, ((void *)0), ((void *)0), ((void *)0), ((void *)0)) # 220 "src/event/ngx_event_openssl.c";if (ngx_ssl_ocsp_index == -1) {ngx_ssl_error(2, log, 0,"SSL_CTX_get_ex_new_index() failed");return -1;}ngx_ssl_certificate_index = # 227 "src/event/ngx_event_openssl.c" 3 4CRYPTO_get_ex_new_index(1, # 227 "src/event/ngx_event_openssl.c"0 # 227 "src/event/ngx_event_openssl.c" 3 4, ((void *)0), ((void *)0), ((void *)0), ((void *)0))# 228 "src/event/ngx_event_openssl.c";if (ngx_ssl_certificate_index == -1) {ngx_ssl_error(2, log, 0,"SSL_CTX_get_ex_new_index() failed");return -1;}ngx_ssl_next_certificate_index = # 235 "src/event/ngx_event_openssl.c" 3 4CRYPTO_get_ex_new_index(3, # 235 "src/event/ngx_event_openssl.c"0 # 235 "src/event/ngx_event_openssl.c" 3 4, ((void *)0), ((void *)0), ((void *)0), ((void *)0))# 236 "src/event/ngx_event_openssl.c";if (ngx_ssl_next_certificate_index == -1) {ngx_ssl_error(2, log, 0, "X509_get_ex_new_index() failed");return -1;}ngx_ssl_certificate_name_index = # 242 "src/event/ngx_event_openssl.c" 3 4CRYPTO_get_ex_new_index(3, # 242 "src/event/ngx_event_openssl.c"0 # 242 "src/event/ngx_event_openssl.c" 3 4, ((void *)0), ((void *)0), ((void *)0), ((void *)0))# 243 "src/event/ngx_event_openssl.c";if (ngx_ssl_certificate_name_index == -1) {ngx_ssl_error(2, log, 0, "X509_get_ex_new_index() failed");return -1;}ngx_ssl_stapling_index = # 250 "src/event/ngx_event_openssl.c" 3 4CRYPTO_get_ex_new_index(3, # 250 "src/event/ngx_event_openssl.c"0 # 250 "src/event/ngx_event_openssl.c" 3 4, ((void *)0), ((void *)0), ((void *)0), ((void *)0)) # 250 "src/event/ngx_event_openssl.c";if (ngx_ssl_stapling_index == -1) {ngx_ssl_error(2, log, 0, "X509_get_ex_new_index() failed");return -1;}return 0; }
可以看出
新版本的初始化
if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {ngx_ssl_error(NGX_LOG_ALERT, log, 0, "OPENSSL_init_ssl() failed");return NGX_ERROR; } ERR_clear_error();
这个分支成立
在 Ubuntu 环境下 使用:
openssl version
也可以查看 openssl 的版本
可以知道 我这里属于 OpenSSL 1.1.0 及以上版本
OPENSSL_init_ssl
在 OpenSSL 1.1.0 及以上版本中,
OPENSSL_init_ssl
函数的声明位于以下头文件中:#include <openssl/ssl.h>
OPENSSL_init_ssl
是 OpenSSL 1.1.0 引入的一个函数,用于初始化 SSL/TLS 库。它的主要作用是替代旧版本中多个独立的初始化函数(如SSL_library_init
、SSL_load_error_strings
等),提供一个统一的接口来完成 SSL/TLS 的初始化工作。函数原型如下:
int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
opts
:
- 这是一个位掩码参数,用于指定初始化选项。
- 常见的选项包括:
OPENSSL_INIT_LOAD_CONFIG
:加载 OpenSSL 配置文件(通常是openssl.cnf
)。OPENSSL_INIT_LOAD_SSL_STRINGS
:加载 SSL/TLS 相关的错误字符串。OPENSSL_INIT_ADD_ALL_CIPHERS
和OPENSSL_INIT_ADD_ALL_DIGESTS
:注册所有加密算法和摘要算法。OPENSSL_INIT_NO_LOAD_CONFIG
:禁用配置文件加载。- 更多选项可以参考 OpenSSL 文档。
settings
:
- 这是一个指向
OPENSSL_INIT_SETTINGS
结构的指针,用于传递更高级的初始化设置。- 在大多数情况下,可以传入
NULL
,表示使用默认设置。2.3 返回值
- 成功时返回
1
。- 失败时返回
0
。需要注意的是,即使
OPENSSL_init_ssl
返回成功,也可能在错误队列中留下未处理的错误信息。因此,通常会在调用后清除错误队列:
ERR_clear_error();
ngx_ssl_error
Ubuntu 下 nginx-1.24.0 源码分析 -ngx_ssl_error 函数-CSDN博客
NGX_ERROR
定义在 src/core/ngx_core.h 中
#define NGX_OK 0 #define NGX_ERROR -1
初始化失败,函数返回 -1
ERR_clear_error
OpenSSL 使用一个线程安全的错误队列来记录操作过程中发生的错误信息。这些错误信息可以通过以下函数访问:
ERR_get_error()
:从错误队列中获取一个错误代码。ERR_peek_error()
:查看错误队列中的第一个错误代码,但不移除它。ERR_clear_error()
:清空当前线程的错误队列。
ERR_clear_error()
的主要作用是清空当前线程的错误队列。具体来说:
- 它会移除所有当前线程中累积的错误信息。
- 调用后,错误队列将变为空状态。
在多线程环境中,每个线程都有独立的错误队列,因此调用
ERR_clear_error()
不会影响其他线程的错误状态
通过调用
ERR_clear_error()
,可以确保错误队列在初始化完成后处于干净的状态。这样,后续的 OpenSSL 操作如果产生错误,错误队列中的信息将是与当前操作直接相关的,而不是之前残留的无关错误
ngx_ssl_connection_index
ngx_ssl_connection_index
是一个全局变量,它的作用是为每个 SSL 连接分配一个唯一的索引值。
这个索引值用于在 OpenSSL 的
SSL
结构体中存储和检索与该连接相关的自定义数据。
ngx_ssl_connection_index
是通过调用SSL_get_ex_new_index()
创建的一个全局索引值
为每个 SSL 连接关联 Nginx 的特定数据 :
- 在 Nginx 中,每个 SSL 连接都需要存储一些与 Nginx 相关的上下文信息(例如连接对象、会话状态等)。
- 通过
ngx_ssl_connection_index
,可以将这些数据存储到 OpenSSL 的SSL
结构体中,并在需要时快速检索。避免全局变量或复杂的数据结构 :
- 如果没有扩展数据机制,Nginx 可能需要维护一个额外的映射表(例如哈希表或链表)来管理 SSL 连接和 Nginx 数据之间的关系。
- 使用
ngx_ssl_connection_index
,可以直接将数据附加到SSL
结构体中,简化了数据管理。
SSL 连接
SSL 连接-CSDN博客
SSL
结构体中的扩展数据数组(ex_data
)不仅仅用于存储用户自定义数据,它还可以被 OpenSSL 内部或其他模块使用。
ngx_ssl_connection_index
是通过SSL_get_ex_new_index()
分配的一个索引值,指向数组中某个特定的位置,而该位置之前的内容可能已经被其他模块或 OpenSSL 内部使用该位置是 用户自定义数据
SSL
结构体中的扩展数据数组是一个固定大小的数组void *ex_data[SSL_MAX_EX_DATA];
SSL_MAX_EX_DATA
:表示数组的最大长度,通常是 32 或更大的一个固定值。- 每个数组元素是一个指针,可以存储任意类型的数据
- 数组的每个槽位由一个整数索引标识。
- 索引值从 0 开始,依次递增。
- 不同的模块或功能可以通过调用
SSL_get_ex_new_index()
分配自己的索引值,并将数据存储到对应的槽位中
SSL_CTX_get_ex_new_index
SSL_CTX_get_ex_new_index()
用于为SSL_CTX
(SSL 上下文)结构体 分配一个扩展数据索引。它的主要作用是:
- 在
SSL_CTX
中存储自定义数据 :例如全局配置、证书链、私钥等。- 支持模块化设计 :允许不同模块将自定义数据附加到
SSL_CTX
中,而无需修改 OpenSSL 的内部实现返回值
- 成功时返回一个非负整数,表示新分配的索引值。
- 失败时返回
-1
。
SSL_get_ex_new_index
的作用
SSL_get_ex_new_index()
用于为SSL
(SSL 连接)结构体 分配一个扩展数据索引。它的主要作用是:
- 在
SSL
中存储自定义数据 :例如每个连接的上下文信息。- 支持连接级别的扩展数据管理 :允许开发者为每个 SSL 连接附加独立的数据
返回值
- 成功时返回一个非负整数,表示新分配的索引值。
- 失败时返回
-1
。
两者的区别
特性
SSL_CTX_get_ex_new_index
SSL_get_ex_new_index
目标结构体
SSL_CTX
(SSL 上下文)
SSL
(SSL 连接)数据范围
全局数据,适用于所有 SSL 连接
每个连接独立的数据
典型用途
存储服务器配置、证书链、会话缓存等全局信息
存储每个连接的上下文信息(如 Nginx 的连接对象)
生命周期
与
SSL_CTX
生命周期一致与单个
SSL
实例的生命周期一致分配的索引值是否共享
不同模块可以分配独立的索引值
不同模块可以分配独立的索引值
SSL_CTX_get_ex_new_index
:用于为SSL_CTX
分配扩展数据索引,适用于存储全局数据(如服务器配置)。SSL_get_ex_new_index
:用于为SSL
分配扩展数据索引,适用于存储每个连接的独立数据(如连接上下文)。- 核心区别 :两者的目标结构体不同,分别对应全局的
SSL_CTX
和每个连接的SSL
。
X509_get_ex_new_index
X509_get_ex_new_index()
是 OpenSSL 提供的一个函数,用于为X509
(证书)结构体 分配扩展数据索引。它的主要作用是:
- 在
X509
结构体中存储自定义数据 :例如与证书相关的上下文信息或元数据。- 支持模块化设计 :允许不同模块将自定义数据附加到
X509
证书对象中,而无需修改 OpenSSL 的内部实现
返回值
- 成功时返回一个非负整数,表示新分配的索引值。
- 失败时返回
-1
。
X509
是 OpenSSL 库中用于表示 数字证书 的核心数据结构。它在 SSL/TLS 协议中扮演着至关重要的角色,主要用于身份验证、加密和信任链的建立
数字证书的核心概念
数字证书是一种电子文档,用于证明某个实体(如服务器或客户端)的身份,并包含该实体的公钥。数字证书通常由受信任的第三方机构(称为 证书颁发机构,CA )签发。
数字证书的主要内容
- 主体信息(Subject) :证书持有者的身份信息(如域名、组织名称等)。
- 公钥(Public Key) :证书持有者的公钥。
- 签发者信息(Issuer) :签发证书的 CA 的身份信息。
- 有效期(Validity Period) :证书的有效时间范围。
- 签名(Signature) :CA 使用其私钥对证书内容进行签名,以确保证书的完整性和真实性
X509
结构体的作用在 OpenSSL 中,
X509
是一个复杂的数据结构,用于表示和操作数字证书。它的主要作用包括以下几个方面:1. 身份验证
- 在 SSL/TLS 握手过程中,服务器会向客户端发送其数字证书(
X509
对象),以证明自己的身份。- 客户端通过验证证书的签名和有效期,确认服务器是否可信。
2. 公钥分发
- 数字证书中包含了服务器的公钥,客户端可以使用该公钥与服务器进行加密通信。
- 例如,在 RSA 密钥交换中,客户端使用服务器的公钥加密预主密钥(Pre-Master Secret)。
3. 建立信任链
- 数字证书通常形成一个信任链(Certificate Chain),从服务器证书到根证书。
X509
提供了操作证书链的功能,例如验证证书链的完整性。4. OCSP 和 CRL 验证
X509
支持在线证书状态协议(OCSP)和证书吊销列表(CRL),用于检查证书是否已被吊销。
数字证书在逻辑上和现实中的证件(如身份证、护照或驾照)非常相似。它们的作用都是用来证明某个实体的身份,并且依赖于一个可信的第三方机构来验证和签发
数字证书与现实证件的核心功能对比
功能
现实中的证件(如身份证)
数字证书
身份证明
证明持证人的身份(如姓名、照片、出生日期等)。
证明某个实体(如服务器或客户端)的身份。
签发机构
由政府或权威机构签发(如公安局)。
由受信任的 CA(证书颁发机构)签发。
有效期
证件有明确的有效期(如 10 年)。
证书有明确的有效期(如 1 年)。
防伪机制
使用防伪技术(如水印、芯片)防止伪造。
使用加密算法(如签名)防止篡改和伪造。
信任链
公众信任签发机构(如政府),从而信任证件。
用户信任 CA,从而信任其签发的证书。
类比:现实中的身份证 vs 数字证书
1. 身份证明
- 现实中的身份证 :
- 身份证上的信息(如姓名、照片、身份证号)用于证明持证人的身份。
- 当你出示身份证时,其他人可以通过检查这些信息确认你是谁。
- 数字证书 :
- 数字证书中的信息(如主体名称、公钥)用于证明某个实体的身份。
- 当服务器向客户端发送证书时,客户端可以通过检查证书内容确认服务器的身份。
2. 签发机构
- 现实中的身份证 :
- 身份证由政府机构(如公安局)签发,公众信任政府,因此也信任身份证的真实性。
- 数字证书 :
- 数字证书由受信任的 CA(如 Let's Encrypt、DigiCert)签发,用户信任 CA,因此也信任其签发的证书。
3. 防伪机制
- 现实中的身份证 :
- 身份证可能包含防伪技术,例如水印、全息图或芯片,以防止伪造。
- 数字证书 :
- 数字证书使用加密算法(如 RSA 或 ECC)生成签名,CA 使用其私钥对证书内容进行签名,确保证书未被篡改。
4. 有效期
- 现实中的身份证 :
- 身份证通常有一个有效期(如 10 年),过期后需要重新申请。
- 数字证书 :
- 数字证书也有一个有效期(如 1 年或 2 年),过期后需要续签或重新申请。
5. 信任链
- 现实中的身份证 :
- 公众信任签发机构(如政府),因此信任其签发的身份证。
- 如果有人伪造身份证,公众可以通过查询政府数据库验证其真实性。
- 数字证书 :
- 用户信任 CA,因此信任其签发的证书。
- 如果证书被篡改或吊销,用户可以通过 CRL(证书吊销列表)或 OCSP(在线证书状态协议)验证其状态。
相关文章:
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_ssl_init 函数
#if (NGX_OPENSSL)ngx_ssl_init(log); #endif objs/ngx_auto_config.h 中 #ifndef NGX_OPENSSL #define NGX_OPENSSL 1 #endif 所以这个条件编译成立 NGX_OPENSSL 是一个宏定义,用于控制与 OpenSSL 相关的功能是否被启用 若用户通过./configure参数(如-…...
时间盲注Boolen盲注之获取表、列、具体数据的函数
时间盲注 时间盲注(Time-Based Blind SQL Injection)是一种利用数据库响应时间的差异来推断数据的SQL注入技术。它的核心原理是通过构造特定的SQL查询,使得数据库在执行查询时产生时间延迟,从而根据延迟的有无来推断数据。 时间…...
人工智能在文化遗产保护中的创新:科技与文化的完美融合
人工智能在文化遗产保护中的创新:科技与文化的完美融合 引言 文化遗产是人类历史的见证,是我们了解过去、感知现在、展望未来的重要宝贵资源。然而,随着时间的流逝,自然灾害、战争、气候变化以及人为因素等,都对文化遗产的保护造成了严峻挑战。传统的文化遗产保护方法虽…...
linux下OSD使用SDL_ttf生成点阵数据,移植+开发代码详解
前言 在做音视频开发的时候,一般会在视频上增加osd水印,时间或者logo之类的,这种水印其实就是由点阵数据构成,本文使用freetypeSDLSDL_ttf生成文字点阵数据,并保存为bmp格式图片。使用这种方式的优点: 方便…...
渗透测试方向的就业前景怎么样?
互联网各领域资料分享专区(不定期更新): Sheet 前言 渗透测试作为网络安全领域的重要分支,近年来就业前景持续向好,尤其在数字化转型加速、安全威胁加剧的背景下,市场需求显著增长。以下是详细分析: 一、市场需求旺盛 …...
SQL Server:查看当前连接数和最大连接数
目录标题 **1. 查看当前连接数****使用系统视图****使用动态管理视图** **2. 查看最大连接数****通过配置选项****通过服务器属性** **3. 查看连接数的实时变化****4. 设置最大连接数****5. 查看连接的详细信息****6. 使用 SQL Server Management Studio (SSMS)****7. 使用 SQL…...
Windows环境搭建ES集群
搭建步骤 下载安装包 下载链接:https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.27-windows-x86_64.zip 解压 解压并复制出3份 es-node1配置 config/elasticsearch.yml cluster.name: xixi-es-win node.name: node-1 path.data: D:\\wor…...
【第15章:量子深度学习与未来趋势—15.3 量子深度学习在图像处理、自然语言处理等领域的应用潜力分析】
一、开篇:为什么我们需要关注这场"量子+AI"的世纪联姻? 各位技术爱好者们,今天我们要聊的这个话题,可能是未来十年最值得押注的技术革命——量子深度学习。这不是简单的"1+1=2"的物理叠加,而是一场可能彻底改写AI发展轨迹的范式转移。 想象这样一个…...
DeepSeek与ChatGPT:AI语言模型的全面对决
DeepSeek与ChatGPT:AI语言模型的全面对决 引言:AI 语言模型的时代浪潮一、认识 DeepSeek 与 ChatGPT(一)DeepSeek:国产新星的崛起(二)ChatGPT:AI 界的开拓者 二、DeepSeek 与 ChatGP…...
DeepSeek-V3模型底层架构的核心技术一(多Token预测(MTP)技术)
一、DeepSeek-V3的框架结构 DeepSeek-V3的框架结构基于三大核心技术构建:多头潜在注意力(MLA)、DeepSeekMoE架构和多token预测(MTP)。这些创新使得模型在处理长序列、平衡计算负载以及生成连贯文本方面表现出色。 1. 基础架构 DeepSeek-V3的基础架构仍然基于Transformer框…...
QT c++ QMetaObject::invokeMethod函数 线程给界面发送数据
在项目开发时,常常需要用线程采集数据,如果要给界面发送数据,本文是方法之二,动态调用。 第一步:在界面类里定义一个带Q_INVOKABLE关键字的函数接收信息 第二步:在线程类里,用 QMetaObject::i…...
netcore https配置
一、生成证书 1. 安装 OpenSSL 如果尚未安装 OpenSSL,可以通过以下命令安装:Ubuntu/Debian:sudo apt update sudo apt install openssl CentOS/RHEL:sudo yum install openssl 2. 生成私钥 使用以下命令生成私钥文件(private.key)…...
centos部署open-webui
提示:本文将简要介绍一下在linux下open-webui的安装过程,安装中未使用虚拟环境。 文章目录 一、open-webui是什么?二、安装流程1.openssl升级2.Python3.11安装3.sqlite安装升级4.pip 下载安装open-webui 总结 一、open-webui是什么? Open W…...
sql语言语法的学习
sql通用语法 sql分类 DDL(操作数据库和表) 操作数据库 操作表_查询 操作表_创建 举例: 操作表_删除 操作表_修改 DML(增删改表中数据) DML添加数据 DML删除数据 DML修改数据 DQL 单表查询 基础查询 条件查询 案例演示: 排序查询 聚合函数 分组查询…...
vueDevtools和文档整合(前端常用工具/插件)
3.vueDevtools安装 chrome插件vue-devtools下载地址: https://chrome.zzzmh.cn/info/nhdogjmejiglipccpnnnanhbledajbpd下载完放到chrome的拓展程序中即可,注意点:vue2和vue3下载版本不同,vue2的话使用稍微老点的版本才行。 详细…...
算法刷题--哈希表--字母异位词和两个数组的交集
哈希表概念 哈希表是根据关键码的值而直接进行访问的数据结构。 直白来讲数组就是一种哈希表。 那么哈希表能解决什么问题呢,一般哈希表都是用来快速判断一个元素是否出现集合里。 那么一般都是将一个集合里面的元素映射为哈希表的索引。 那么设计哈希表的时候需要…...
150,[5] BUUCTF WEB [BJDCTF2020]EasySearch
进入靶场 有个文件 和之前一道题如出一辙 <?php// 开启输出缓冲,将后续所有的输出内容先暂存到缓冲区,而不是直接发送到浏览器ob_start();/*** 生成一个基于随机字符串和唯一标识符的哈希值* return string 返回生成的 sha1 哈希值*/function get_…...
kibana es 语法记录 elaticsearch
目录 一、认识elaticsearch 1、什么是正向索引 2、什么是倒排索引 二、概念 1、说明 2、mysql和es的对比 三、mapping属性 1、定义 四、CRUD 1、查看es中有哪些索引库 2、创建索引库 3、修改索引库 4、删除索引库 5、新增文档 6、删除文档 5、条件查询 一、认识…...
以若依移动端版为基础,实现uniapp的flowable流程管理
1.前言 此代码是若依移动端版为基础,实现flowable流程管理,支持H5、APP和微信小程序三端。其中,APP是在安卓在雷电模拟器环境下完成的,其他环境未测试,此文章中所提及的APP均指上述环境。移动端是需要配合若依前后端分…...
SaaS 平台开发要点
如何在 SaaS 平台的前端开发中,编写高性能、高质量且高度通用化的 Vue 组件 一、组件设计原则 单一职责原则:每个组件只负责一个核心功能受控/非受控模式:同时支持 v-model 和自主状态管理组合式 API:使用 Composition API 提升逻辑复用性可访问性:遵循 WAI-ARIA 规范Typ…...
【Kubernetes】k8s 部署指南
1. k8s 入门 1.1 k8s 简介 需要最需要明确的就是:kubernetes(简称 k8s ) 是一个 容器编排平台 ,换句话说就是用来管理容器的,相信学过 Docker 的小伙伴对于容器这个概念并不陌生,打个比方:容器…...
【Linux】进程间关系与守护进程
文章目录 1. 进程组2. 会话2.1 什么是会话2.2 如何创建会话2.3 守护进程 3. 作业控制 1. 进程组 我们运行下面的命令 sleep 10000 | sleep 20000 | sleep 30000然后查看进程的信息: 可以看到,其实每一个进程除了有进程PID、PPID之外,还属于…...
如何通过AI让PPT制作更轻松:从AI生成PPT到一键智能生成
如何通过AI让PPT制作更轻松:从AI生成PPT到一键智能生成!在这个信息爆炸的时代,PPT几乎成了每个人办公必备的工具。但说到制作PPT,很多人头疼不已——排版、设计、内容的整理,时间一不小心就被浪费掉了。有没有一种方法…...
解决前后端日期传输因时区差异导致日期少一天的问题
前端处理 1. 发送日期字符串而非时间戳 在前端使用日期选择器(如 el-date-picker)获取日期后,将日期转换为特定格式的字符串(如 YYYY-MM-DD)发送给后端,避免直接发送带有时区信息的时间戳或日期对象。这样…...
vue2和vue3生命周期的区别通俗易懂
用最直白的对比帮你理解 Vue2 和 Vue3 生命周期的区别,就像对比手机系统的升级: 一、生命周期阶段对比表(老手机 vs 新手机) 阶段Vue2(老系统)Vue3(新系统)变化说明初始化beforeCre…...
在 Ubuntu 20.04 为 Clash Verge AppImage 创建桌面图标教程
在 Ubuntu 20.04 为 AppImage 创建桌面图标教程 一、准备工作 确保你已经下载了 xxxx.AppImage 文件,并且知道它所在的具体路径。同时,你可以准备一个合适的图标文件(.png 格式)用于代表该应用程序,如果没有合适的图…...
Dockerfile 编写推荐
一、导读 本文主要介绍在编写 docker 镜像的时候一些需要注意的事项和推荐的做法。 虽然 Dockerfile 简化了镜像构建的过程,并且把这个过程可以进行版本控制,但是不正当的 Dockerfile 使用也会导致很多问题。 docker 镜像太大。如果你经常使用镜像或者…...
Flutter 中的生命周期
在 Flutter 中,StatefulWidget 和 StatelessWidget 这两种 Widget 的生命周期不同,主要关注的是 StatefulWidget,因为它涉及到状态的管理和更新。 StatefulWidget 的生命周期: 1. 创建阶段 (Create) createState():…...
AI大模型的文本流如何持续吐到前端,实时通信的技术 SSE(Server-Sent Events) 认知
写在前面 没接触过 SSE(Server-Sent Events),AI大模型出来之后,一直以为文本流是用 WebSocket 做的偶然看到返回到报文格式是 text/event-stream,所以简单认知,整理笔记博文内容涉及 SSE 认知,以及对应的 D…...
项目版本号生成
需求 项目想要生成一个更新版本号,格式为v2.0.20250101。 其中v2.0为版本号,更新时进行配置;20250101为更新日期,版本更新时自动生成。 实现思路 创建一个配置文件version.properties,在其中配置版本号;…...
Spring AI发布!让Java紧跟AI赛道!
1. 序言 在当今技术发展的背景下,人工智能(AI)已经成为各行各业中不可忽视的重要技术。无论是在互联网公司,还是传统行业,AI技术的应用都在大幅提升效率、降低成本、推动创新。从智能客服到个性化推荐,从语…...
ubuntu服务器 如何配置安全加固措施
下面提供一个更详细、一步步的服务器安全加固指南,适合新手操作。我们将从 Fail2Ban、SSH(密钥认证及端口更改)、Nginx 速率限制和日志轮转四个方面进行优化,同时补充一些额外的安全建议。 新的服务器,通常我们会创建一…...
京东java面试流程_java京东社招面试经历
个人背景:java开发工作2年,跳槽2次,被裁一次,无大厂经历,京东内推。整体感觉不错的面试经历,最后败了。 一、面试流程 (1)上机题(60分钟100道选择题,单选多选混合的) (2)技术面(java基础知识…...
多表查询、事务(MySQL笔记第三期)
p.s.这是萌新自己自学总结的笔记,如果想学习得更透彻的话还是请去看大佬的讲解 目录 多表关系多表查询内连接外连接左外连接右外连接 自连接联合查询子查询标量子查询列子查询行子查询表子查询 例题事务方式一方式二事务四大特性(ACID)并发事务问题隔离事务级别 多…...
python电影数据分析及可视化系统建设
博主介绍:✌程序猿徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
【06】泛型
文章目录 泛型函数中的泛型结构体中的泛型结构体中的方法 枚举中的泛型 泛型 RUST通过在编译时对泛型代码的单态化(monomorphization)来保证运行效率。即,在编译时对泛型填充具体数据类型转换为特定代码进行编译。 由于RUST编译试图穷举所有…...
C# 鼠标点击ToolStripStatuslabel 在线修改Text属性并存储加载显示Text属性
在实际项目中为方便了解视觉软件的使用性,可能需要添加一些小而稍微实用的功能:一个StipStatus控件上的Label按钮属性Text需要修改并保存,软件重启后能够自动加载修改后的属性名。 定义变量 public static string controlsText System.Windows.Forms.A…...
Deep seek学习日记1
Deepseek最强大的就是它的深度思考,并且展现了它的思考过程。 五种可使用Deep seek的方式(应该不限于这五种,后续嵌入deepseek的应该更多,多了解一点因为官网容易崩~~): 1.deep seek官网 2.硅基流动silicon…...
我的docker随笔46:在x86平台构建龙芯镜像
本文介绍在x86服务器上构建龙芯平台的docker镜像。 前言 去年11月,在龙芯机器上安装了docker工具,并开始尝试研究如何构建龙芯的文件系统。断断续续搞了2个月后,有点结果出来了。前面有文章介绍了如何用debootstrap构建龙芯编译运行环境&…...
某大型业务系统技术栈介绍【应对面试】
微服务架构【图】 微服务架构【概念】 微服务架构,是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。在微服务架构中,服务与服务之间通信时,通常是…...
wordpress资讯类网站整站打包
wordpress程序,内置了价值499元的模板.但是有了模板没有全自动采集相信大多数人都搞不懂,目录那么多,全靠原创几乎是不可能的事情,除非你是大公司,每人控制一个板块, 这套源码里面最有价值的应该是这个采集…...
移动端测试的挑战与解决方案:兼容性、网络问题及实战策略
引言 移动应用已成为用户触达服务的核心入口,但移动端测试面临设备多样性、网络波动、用户场景复杂等多重挑战。据Statista统计,2023年全球活跃移动设备超180亿台,操作系统(Android/iOS)版本碎片化率超30%,这对测试工程师提出了极高要求。本文深度解析移动端测试的核心痛…...
基于JAVA的幼儿园管理系统的设计与实现源码(springboot+vue+mysql)
项目简介 幼儿园管理系统实现了以下功能: 基于JAVA的幼儿园管理系统的设计与实现的主要使用者管理员可以管理系统基本信息;管理轮播图、系统简介、教师管理、课程管理、幼儿活动管理、餐饮管理、留言管理等功能;前台用户注册登录࿰…...
【Java学习】二维数组
一个数组变量里存的是哈希值(存的大小内容是固定的),它指向对应在堆区上的数组空间,当一个数组变量里存的哈希值指向的在堆上的数组空间里面的一个个引用元素存储的是一个个哈希值指向在堆区上的又一个个数组空间时,此时就形成了二维数组&…...
express + vue 部署宝塔
域名备案 我这里是不同的账号,需要先登录服务器的账号生成授权码给到对应域名的账号。目前域名审核中。 进入域名账号,进行备案即可。 登录阿里云密码设置 未设置登录远程服务的密码,要先设置密码。 登录服务 设置安全组 根据宝塔的需要端…...
前端与后端的对接事宜、注意事项
前端与后端的对接事宜、注意事项 一、对接核心流程(完整生命周期) #mermaid-svg-6yzij6OD8DKqiMLD {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6yzij6OD8DKqiMLD .error-icon{fill:#552222;}#mermaid-svg-6yzi…...
【计算机网络】传输层数据段格式
在计算机网络中,数据段(Segment) 是传输层协议(如 TCP 或 UDP)使用的数据单元。TCP 和 UDP 的数据段格式有所不同,以下是它们的详细说明: 1. TCP 数据段格式 TCP(传输控制协议&…...
web第三次作业
弹窗案例 1.首页代码 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>综合案例</title><st…...
深度学习(1)-简单神经网络示例
我们来看一个神经网络的具体实例:使用Python的Keras库来学习手写数字分类。在这个例子中,我们要解决的问题是,将手写数字的灰度图像(28像素28像素)划分到10个类别中(从0到9)。我们将使用MNIST…...
DeepSeek 模型部署与使用技术评测(基于阿里云零门槛解决方案)
引言 随着人工智能技术的不断发展,越来越多的企业和个人开始探索如何利用深度学习模型来提升业务效率和用户体验。阿里云推出的【零门槛、轻松部署您的专属 DeepSeek 模型】解决方案为用户提供了多种便捷的部署方式,包括基于百炼 API 调用满血版、基于人…...