Curl 可以说是非常流行的一个客户端网络请求工具,充分理解了 Curl,相当于熟练掌握了 HTTP/HTTPS 协议(也包括其他的应用层协议,比如 FTP、IMAP 等等)。
一旦将 Curl 和 HTTPS 协议联系在一起,对于初学者来说,必然会思考以下几个问题:
- Curl 是如何完成 HTTPS 协议交互的?
- Curl 是基于 OpenSSL、Nss,还是其他密码学库实现的 HTTPS 功能?
- 和浏览器一样,Curl 为校验证书,其依赖的根证书库位置在哪儿?
- 使用包安装(apt或yum)和源代码安装 Curl 有什么区别?
在我写的书《深入浅出HTTPS:从原理到实战》也描述了 Curl 和 HTTPS 的交互,但由于各方面原因,讲解的不是特别深入,所以打算写几篇相关的文章解释这些问题,这篇文章主要基于 Ubuntu(14.4 版本) 的 apt 包安装工具讲解 Curl 和 HTTPS 相关知识,如何你对 apt 包安装工具不熟悉,也可以借此篇文章学习。
在 Ubuntu 下,为支持 HTTPS 协议,Curl 安装的时候默认使用的是 OpenSSL 密码库;在 CentOS 下,Curl 安装的时候默认使用的是 NSS 密码库。
首先看看 curl 依赖于哪些包,执行如下命令:
$ apt-cache depends curl
输出如下:
curl
依赖: libc6
依赖: libcurl3
依赖: zlib1g
冲突: curl:i386
依赖最重要的包就是 libcurl3,执行如下命令,看看 libcurl3 依赖什么包:
$ apt-cache depends libcurl3
输出如下:
libcurl3
依赖: libc6
依赖: libgssapi-krb5-2
依赖: libidn11
依赖: libldap-2.4-2
依赖: librtmp0
并没有看到 OpenSSL 的影子,难道 libcurl3 没有包含 OpenSSL 相关库?
再仔细阅读 libcurl3 包的说明,执行下列命令:
$ apt-cache show libcurl3
结果见下图:
其中有两点重点关注:
- Recommends: ca-certificates,推荐安装 ca-certificates 包,非常有用,后续我会专门描述。
- SSL support is provided by OpenSSL,说明 libcurl3 的 SSL 功能确实由 OpenSSL 提供。
那么为什么从 libcurl3 包中看不到 OpenSSL 的影子呢?让我们拿出 ldd 大法,执行下列命令:
ldd /usr/bin/curl | grep ssl
关键输出如下:
libssl.so.1.1 => /usr/lib/x86_64-linux-gnu/libssl.so.1.1 (0x00007fd25e60a000)
原来是 libcurl3 静态绑定了 libssl.so.1.1,这个包是 OpenSSL 提供的吗?通过两种方法验证。
(1)查看包依赖关系
$ apt-cache depends openssl
输出:
openssl
依赖: libc6
依赖: libssl1.0.0
建议: ca-certificates
冲突: openssl:i386
可以看出 openssl 也依赖 libssl1.0.0。
同时 libssl1.0.0 也提供给 libcurl3,可以执行下列命令进行确认:
$ apt-cache rdepends libssl1.0.0 | grep curl
libcurl3
(2)通过 curl-config
这个工具非常有用,官方介绍如下:
curl-config - Get information about a libcurl installation
也就是说,通过 apt 包安装 curl 虽然简单,但失去了解细节的乐趣(比如无法知晓编译了那些具体参数),而 curl-config 工具可以让你了解内幕。
如果机器没有该工具,可以使用下列命令安装:
$ apt-get install libcurl4-openssl-dev
$ dpkg -L libcurl4-openssl-dev
然后重点观察 apt 安装采用的 configure,执行如下命令:
$ curl-config --configure
输出如下:
'--build=x86_64-linux-gnu' '--prefix=/usr' '--includedir=/usr/include' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--sysconfdir=/etc' '--localstatedir=/var' '--libdir=/usr/lib/x86_64-linux-gnu' '--libexecdir=/usr/lib/x86_64-linux-gnu' '--disable-maintainer-mode' '--disable-dependency-tracking' '--disable-symbol-hiding' '--enable-versioned-symbols' '--enable-threaded-resolver' '--with-lber-lib=lber' '--with-gssapi=/usr' '--with-ca-path=/etc/ssl/certs' 'build_alias=x86_64-linux-gnu' 'CFLAGS=-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security' 'LDFLAGS=-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,--as-needed' 'CPPFLAGS=-D_FORTIFY_SOURCE=2'
--with-ca-path 这个参数可以重点关注,curl 在校验服务器证书的时候,会使用该目录下的根证书库文件,在 Ubuntu 中,/etc/ssl/certs 是 OpenSSL 库配置的根证书库(是不是很想改为 NSS 可信任根证书库?后续文章我会描述)。
上述命令并没有 ssl 包相关信息,可以执行下列命令查看静态编译的库:
$ curl-config --static-libs
输出如下:
/usr/lib/x86_64-linux-gnu/libcurl.a -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,--as-needed -lidn -lrtmp -lssl -lcrypto -lssl -lcrypto -Wl,-Bsymbolic-functions -Wl,-z,relro -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -llber -llber -lldap -lz
如果你没有安装 Curl,执行一条命令就能完成(前提你安装了 OpenSSL,Ubuntu 默认会安装):
$ apt-get install curl
看看 Curl 安装后的信息,执行如下命令:
$ curl -V
输出信息如下:
curl 7.58.0 (x86_64-pc-linux-gnu) libcurl/7.58.0 OpenSSL/1.1.0g zlib/1.2.8 nghttp2/1.31.0-DEV
Release-Date: 2018-01-24
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy
可见 curl 基于 libcurl/7.58.0 和 OpenSSL/1.1.0g。
然后再执行下 curl https 请求命令:
$ curl -v "https://www.baidu.com"
输出信息如下图:
重点关注的细节是 curl 使用的可信任根证书库 CAfile: /etc/ssl/certs/ca-certificates.crt。后续会重点讲解 Curl 使用的根证书库。
我最近写了一本书《深入浅出HTTPS:从原理到实战》,欢迎去各大电商购买,也欢迎关注我的公众号(yudadanwx,虞大胆的叽叽喳喳),了解我最新的博文和本书。