OpenSSL这个库应用非常广泛,实际业务环境中使用广泛的Nginx、SSH都有用到,一旦使用了漏洞版本则可能产生安全问题。之前在个人公众号isgenie发布过《一个关于OpenSSL和Nginx的漏洞修复过程》和《Nginx编译并动态链接OpenSSL库》,上述两文中编译安装了Nginx。本文对动态编译Nginx程序时链接不同版本的OpenSSL库进行对比说明,并深入一点说说实验中的编译过程。
一、Nginx和OpenSSL编译实验环境
操作系统版本:CentOS 7
Nginx源码版本:1.18.0
Nginx源码路径:/home/nginx-1.18.0
旧OpenSSL动态库版本:1.0.2k-fips
新OpenSSL源码版本:1.1.1j
新OpenSSL源码路径:/home/openssl-1.1.1j
GCC版本:4.8.5
二、对比两次动态链接编译
这里复现了两次使用OpenSSL动态链接库的编译,分别使用新旧版本的OpenSSL库。第一次使用旧库,旧库通过YUM安装,编译后的文件为图中的nginx.old。新库通过源码编译安装,并配置好相应的环境,编译后的文件为图中的nginx。分别执行程序查看版本信息对比如下:
![](https://i-blog.csdnimg.cn/blog_migrate/bfcdf4191a8679401d220d9c9d7bdb1b.png)
上图可见,nginx的版本是相同的,但是OpenSSL的版本不一样。
使用OpenSSL旧库
编译完成后,动态库链接情况如下:
![](https://i-blog.csdnimg.cn/blog_migrate/b5d9c178447a319e35917319c6aee3c5.png)
使用OpenSSL新库
编译完成后,动态库链接情况如下:
![](https://i-blog.csdnimg.cn/blog_migrate/e55f23fcbf580ebf581df33aedff4455.jpeg)
两次使用动态链接库的差异
我们可以看到libssl.so和libcrypt.so两个库是不一样的。链接OpenSSL旧库时使用的是libssl.so.10和libcrypto.so.10,而链接OpenSSL新库时使用的是libssl.so.1.1和libcrypto.so.1.1。
三、编译
那为什么更新OpenSSL动态链接库后编译能链接到对应版本的库呢?原因在于头文件,编译器编译时会根据nginx源码的预处理命令默认到 /usr/include/ 下查找相应的头文件,然后就能链接到对应的库了。如果库的头文件不在 /usr/include/ 中,那么编译时就需要用“-I”(大写i)参数指定头文件所在的路径。
那动态库链接是如何进行的呢?下面简单说说编译的过程。
编译过程
编译的过程主要包括4个步骤,每个步骤逐一完成:
预处理->编译->汇编->链接
各个步骤工作如下:
预处理:处理所有以#开头的代码,包括头文件、宏定义、条件编译
编译:语法检查以及将C语言变成汇编语言
汇编:将汇编语言变成二进制文件
链接:链接代码需要用到的其它文件(库文件等)
Nginx源码编译
实验中使用如下命令生成Makefile和编译需要的源码文件
./configure --with-http_ssl_module --with-http_gzip_static_module --with-poll_module --with-file-aio --with-http_realip_module --with-http_addition_module --with-http_addition_module --with-http_random_index_module --with-http_stub_status_module --http-uwsgi-temp-path=/usr/local/nginx/uwsgi_temp --with-stream
这里使用了OpenSSL动态链接库,打开Makefile文件查看,找到$(LINK)宏命令行,拉到下方可以找到指定了ssl库(红框处)。动态库的查找规则是
【lib+库名.so】,所以这里查找的是libssl.so这个文件。
![](https://i-blog.csdnimg.cn/blog_migrate/c4ca09c84aeb30f3a66cd6bd6abd8536.png)
库文件的查找路径可以通过如下命令查看。
ldconfig -v
实验主机在/usr/lib64/ 中找到libssl.so,进行链接。在 /usr/lib64/ 中可以找到多个libssl库文件和软连接。我们会看到libssl.so和libssl.so.soname形式命名的文件,通常带有发布版本后缀的库文件才是真正的库文件。以下图的文件为例,libssl.so和libssl.so.10都链接libssl.so.1.0.2k,这里的libssl.so是给编译器使用的,而libssl.so.10是给动态连接器使用的。
![](https://i-blog.csdnimg.cn/blog_migrate/ce1b226cf94c55980bae3c6d70d4e8e6.png)
总结
编译时用到的动态链接库,需要保持头文件和库文件的一致,并确保编译器能找到对应文件。通常头文件默认到 /usr/include/ 中查找,库文件默认到 /usr/lib64/ (和其他默认或ld配置环境)中查找,但不同的环境查找路径会有差异。