curl
要让 curl 基于 NSS(Network Security Services)构建,你需要满足以下几个条件:
✅ 一、使用已经基于 NSS 构建的 curl(推荐)
最简单的方式是:使用 RHEL / CentOS / Rocky / AlmaLinux 等发行版的系统自带 curl。
你可以运行以下命令验证是否已经是 NSS 构建:
curl -V
如果输出包含:
curl 7.xx.x (...) libcurl/7.xx.x NSS/3.xx
说明你已经是在使用基于 NSS 的 curl,不需要手动构建。
✅ 二、手动构建基于 NSS 的 curl(高级做法)
如果你想在其他系统(比如 Ubuntu 或 Arch)上编译一个使用 NSS 的 curl,你可以按照以下流程操作:
1. 安装依赖包(以 CentOS 7 为例)
sudo yum groupinstall "Development Tools"
sudo yum install nss nss-devel libcurl-devel zlib-devel libidn2-devel
2. 下载并解压 curl 源码
curl -LO https://curl.se/download/curl-8.6.0.tar.gz
tar -xzf curl-8.6.0.tar.gz
cd curl-8.6.0
3. 配置并指定 NSS 作为 SSL backend
./configure --with-nss --disable-ldap --prefix=/usr/local/curl-nss
make -j$(nproc)
sudo make install
4. 验证
/usr/local/curl-nss/bin/curl -V
应输出:
curl 8.6.0 (x86_64-pc-linux-gnu) libcurl/8.6.0 NSS/3.92 ...
✅ 三、注意事项
-
NSS 是 Mozilla 提供的 TLS 实现,在 curl 中并不是主流,OpenSSL 是最常见的。
-
Ubuntu/Debian 上的 curl 默认使用 OpenSSL 或 GnuTLS,除非手动指定。
-
NSS 主要出现在 CentOS / RHEL 系统默认安装的 curl 中。
✅ 可选:查看系统中现有的 curl 构建信息
运行:
ldd $(which curl)
可以看到链接了哪个 TLS 库:
-
libnss3.so表示使用 NSS。 -
libssl.so表示使用 OpenSSL。 -
libgnutls.so表示使用 GnuTLS。
如果你告诉我你的操作系统和目标用途,我可以提供更具体的建议,比如是否值得使用 NSS。需要我帮你写一个构建脚本也可以~
你的问题是:
为什么有些
curl -kvL请求会输出 TLS 协商信息(比如使用了哪个 Cipher Suite),而有些却不显示?
比如:
-
https://www.baidu.com显示了:* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 -
但
https://map.naver.com却没有这一行,或者显示方式不同。
✅ 原因总结:
1. 不同 SSL 实现(NSS vs OpenSSL)显示方式不同
这其实是最根本的原因!
-
在你访问
www.baidu.com的日志中出现了:* Initializing NSS with certpath: sql:/etc/pki/nssdb说明你这台机器的
curl是基于 NSS (Network Security Services) 构建的(常见于 RHEL/CentOS 上)。 -
而访问
map.naver.com的输出是:* [CONN-1-0][CF-SSL] TLSv1.2 ...说明你用的是另一个版本的
curl,很可能是基于 libcurl + OpenSSL,或者有启用 Cloudflare 的连接跟踪功能([CF-*]就是 Cloudflare/Chromium-style logging)——这类构建可能不会用相同的输出格式打印 Cipher 信息。
不同构建方式输出 TLS 协商细节的风格完全不同,有的详细、有的简略。
2. 是否使用了 -v 和输出风格差异
-
-v仅保证输出详细信息,但具体显示哪些 TLS 细节,是curl编译时链接的 SSL 库决定的。 -
有些构建下
-v会打印:* SSL connection using ... -
而有些构建(比如
libcurl + OpenSSL)可能只显示握手流程,不专门输出 negotiated cipher。
3. 不同目标站点服务器的 TLS 响应速度或中间件行为
-
某些服务器(尤其是 CDN 站)可能做了 TLS 中间转发,或者 TLS 握手是在另一个中间节点完成的,导致输出略不同。
-
但这个影响较小,主要还是客户端
curl构建方式不同。
✅ 如何验证当前 curl 使用了哪个 SSL 库?
运行:
curl -V
输出会类似:
curl 7.76.1 (x86_64-redhat-linux-gnu) libcurl/7.76.1 NSS/3.67
或:
curl 8.5.0 (x86_64-pc-linux-gnu) libcurl/8.5.0 OpenSSL/3.0.8
-
如果是 NSS:你会看到
NSS/xxx,这会显示 “SSL connection using...” 这一行。 -
如果是 OpenSSL 或 wolfSSL:则输出方式不同,不一定有那一行。
✅ 想强制查看 Cipher 使用情况?
你可以加上 --trace 或 --trace-ascii,甚至用 openssl s_client 查看。
比如:
openssl s_client -connect www.baidu.com:443 -servername www.baidu.com
会看到 negotiated cipher:
...
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
...
✅ 总结
| 情况 | 是否显示 TLS 协商信息 | 原因 |
|---|---|---|
使用 curl + NSS |
✅ 有 * SSL connection using ... |
NSS 显示习惯 |
使用 curl + OpenSSL |
❌ 可能没有该信息 | 显示风格不同 |
使用 curl -v |
✅ 显示握手过程 | 是否有 negotiated cipher 依赖构建 |
| 使用 CDN 或中间代理的站点 | 可能影响 handshake 输出细节 | 但不是主要因素 |
如果你愿意,把你运行 curl -V 的输出贴出来,我可以帮你准确判断是哪种构建方式。
你贴的是一个 curl 命令的完整执行过程,内容非常丰富,涉及:
-
HTTP 请求跳转(301 / 302)
-
TLS 握手完整过程
-
User-Agent 伪装行为
-
curl 日志调试信息
-
最终 HTML 页面返回
下面我会从这几个方面给你做一个全流程分析,尤其会重点分析 TLS 过程,并用 markdown 格式画出流程图和字段解释。
一、整体流程简述
你执行的命令是:
curl -kvL -H "User-Agent: Mozilla/5.0 (...) 360Spider SogouSpider" http://map.naver.com/
参数说明:
-
-k:忽略 HTTPS 证书校验错误
-
-v:输出详细调试信息(verbose)
-
-L:跟随 3xx 跳转
-
-H:设置请求头,这里是 User-Agent(模拟蜘蛛爬虫)
请求流程大致如下:
-
向 http://map.naver.com 发起请求(明文 HTTP 80 端口)
-
收到 302 跳转到 https://map.naver.com/
-
重新用 HTTPS 建立连接(443 端口)
-
TLS 握手开始
-
TLS 握手完成(协商出密钥、对称加密方式等)
-
发送 GET 请求(加密的)
-
收到 301 跳转到 https://map.naver.com/p/
-
跟随跳转,再次发起 GET 请求
-
返回 HTML 页面(HTTP 200)
二、TLS 握手详细过程分析(重点)
TLS(Transport Layer Security)握手主要是用来建立安全连接(加密通信)的协议协商过程。
你的 curl 输出中涉及的 TLS 日志如下:
* [CF-SSL] TLSv1.2 (OUT), TLS handshake, Client hello (1)
* [CF-SSL] TLSv1.2 (IN), TLS handshake, Server hello (2)
* [CF-SSL] TLSv1.2 (IN), TLS handshake, Certificate (11)
* [CF-SSL] TLSv1.2 (IN), TLS handshake, Server key exchange (12)
* [CF-SSL] TLSv1.2 (IN), TLS handshake, Server finished (14)
* [CF-SSL] TLSv1.2 (OUT), TLS handshake, Client key exchange (16)
* [CF-SSL] TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1)
* [CF-SSL] TLSv1.2 (OUT), TLS handshake, Finished (20)
* [CF-SSL] TLSv1.2 (IN), TLS change cipher, Change cipher spec (1)
* [CF-SSL] TLSv1.2 (IN), TLS handshake, Finished (20)
这些是 TLS 1.2 中标准的 10 步握手流程:
🔒 TLS 1.2 握手流程图(markdown 格式)
sequenceDiagram
participant Client
participant Server
Client->>Server: Client Hello (版本、支持的加密算法、随机数)
Server->>Client: Server Hello (选择的版本、算法、随机数)
Server->>Client: Certificate (服务器证书)
Server->>Client: Server Key Exchange(如果需要 DH 密钥参数)
Server->>Client: Server Hello Done
Client->>Server: Client Key Exchange(传送加密的 pre-master key)
Client->>Server: Change Cipher Spec
Client->>Server: Finished(加密完成信号)
Server->>Client: Change Cipher Spec
Server->>Client: Finished(加密完成信号)
Note over Client,Server: 双方切换为对称加密通信(SSL 加密隧道建立)
🧠 各字段说明(TLS handshake 消息类型)
| ID | 名称 | 描述 |
|---|---|---|
| 1 | Client Hello | 客户端发起握手,请求 TLS 连接 |
| 2 | Server Hello | 服务器响应,确认协议版本和加密算法 |
| 11 | Certificate | 服务器发给客户端的证书链(包含公钥) |
| 12 | Server Key Exchange | 若使用 DH/ECDHE,提供 DH 参数 |
| 14 | Server Hello Done | 表示服务器消息发送完毕 |
| 16 | Client Key Exchange | 客户端用服务器公钥加密 pre-master key |
| 20 | Finished | 通信加密的结束信号,表示握手完毕 |
| 1 | Change Cipher Spec | 通知对方:之后的消息都是加密的 |
👁️🗨️ 如何看懂 curl 的 TLS 日志
关键点:
-
“(OUT)” 表示客户端发送的消息
-
“(IN)” 表示服务端返回的消息
-
Certificate verify result: 20 — 表示证书链不完整(但你用了 -k 忽略)
比如:
* [CF-SSL] TLSv1.2 (IN), TLS handshake, Certificate (11)
说明 curl 收到了服务器的证书(用于身份认证)
而:
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
是因为你的本地 curl 没有安装 DigiCert 的根证书或者中间证书(但 -k 跳过验证了)
三、后续 HTTP 重定向流程
你经历了两次重定向:
-
HTTP 302 → https://map.naver.com/
-
HTTPS 301 → https://map.naver.com/p/
这两个状态码含义如下:
-
302 Found:临时重定向,用户可以继续使用原 URL
-
301 Moved Permanently:永久重定向,客户端应更新 URL
四、最终页面返回分析
最终 GET https://map.naver.com/p/ 得到 HTTP 200,返回的是 HTML 页面,其中包含了前端资源(JS、icon、manifest 等),表明页面是一个 SPA(单页面应用):
<script src="https://maps-service.pstatic.net/pcweb_navermap_v5/...">
五、你能如何进一步理解 TLS?
建议你:
-
用 Wireshark 抓包,观察 TLS 报文内容(看 TLS Record Layer)
-
使用 openssl 验证服务器证书链:
openssl s_client -connect map.naver.com:443 -
用 curl 关闭 -k 参数,看 curl 的报错是否变成证书链错误
如你还想:
-
分析 TLS 1.3 的握手流程(更快,只需 1-RTT)
-
了解对称加密 vs 非对称加密在 TLS 中的使用
-
抓包解码 TLS 内容(需要服务器配合)
我也可以继续帮你。
是否需要我再把上面流程图用图片画出来?还是你想继续深入某个字段?
$ curl -kvL -H "User-Agent:Mozilla/5.0 ((Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36; 360Spider SogouSpider" http://map.naver.com/ * [CONN-0-0][CF-TCP] connect * Trying 110.93.151.134:80... * [CONN-0-0][CF-TCP] connect opened(6) * [CONN-0-0][CF-TCP] connect * [CONN-0-0][CF-TCP] connect * [CONN-0-0][CF-TCP] connect * Connected to map.naver.com (110.93.151.134) port 80 (#0) * [CONN-0-0][CF-TCP] send(len=203) -> 203, err=0 > GET / HTTP/1.1 > Host: map.naver.com > Accept: */* > User-Agent:Mozilla/5.0 ((Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36; 360Spider SogouSpider > * [CONN-0-0][CF-TCP] recv(len=102400) -> 100, err=0 < HTTP/1.1 302 Found < content-length: 0 < location: https://map.naver.com/ < cache-control: no-cache < * Connection #0 to host map.naver.com left intact * Clear auth, redirects to port from 80 to 443 * Issue another request to this URL: 'https://map.naver.com/' * [CONN-1-0][CF-TCP] connect * Trying 110.93.151.134:443... * [CONN-1-0][CF-TCP] connect opened(7) * [CONN-1-0][CF-TCP] connect * [CONN-1-0][CF-TCP] connect * Connected to map.naver.com (110.93.151.134) port 443 (#1) * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * [CONN-1-0][CF-TCP] send(len=517) -> 517, err=0 * [CONN-1-0][CF-SSL] TLSv1.2 (OUT), TLS Unknown, Certificate Status (22): * [CONN-1-0][CF-SSL] TLSv1.2 (OUT), TLS handshake, Client hello (1): * [CONN-1-0][CF-TCP] recv(len=7) -> -1, err=81 * [CONN-1-0][CF-TCP] recv(len=7) -> 7, err=0 * [CONN-1-0][CF-TCP] recv(len=91) -> 91, err=0 * [CONN-1-0][CF-SSL] TLSv1.2 (IN), TLS handshake, Server hello (2): * [CONN-1-0][CF-TCP] recv(len=5) -> 5, err=0 * [CONN-1-0][CF-TCP] recv(len=2946) -> 2946, err=0 * [CONN-1-0][CF-SSL] TLSv1.2 (IN), TLS handshake, Certificate (11): * [CONN-1-0][CF-TCP] recv(len=5) -> 5, err=0 * [CONN-1-0][CF-TCP] recv(len=148) -> 148, err=0 * [CONN-1-0][CF-SSL] TLSv1.2 (IN), TLS handshake, Server key exchange (12): * [CONN-1-0][CF-TCP] recv(len=5) -> 5, err=0 * [CONN-1-0][CF-TCP] recv(len=4) -> 4, err=0 * [CONN-1-0][CF-SSL] TLSv1.2 (IN), TLS handshake, Server finished (14): * [CONN-1-0][CF-SSL] TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * [CONN-1-0][CF-SSL] TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * [CONN-1-0][CF-SSL] TLSv1.2 (OUT), TLS handshake, Finished (20): * [CONN-1-0][CF-TCP] send(len=126) -> 126, err=0 * [CONN-1-0][CF-TCP] recv(len=5) -> -1, err=81 * [CONN-1-0][CF-TCP] recv(len=5) -> 5, err=0 * [CONN-1-0][CF-TCP] recv(len=1) -> 1, err=0 * [CONN-1-0][CF-SSL] TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * [CONN-1-0][CF-TCP] recv(len=5) -> 5, err=0 * [CONN-1-0][CF-TCP] recv(len=40) -> 40, err=0 * [CONN-1-0][CF-SSL] TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-ECDSA-AES128-GCM-SHA256 * Server certificate: * subject: C=KR; ST=Gyeonggi-do; L=Seongnam-si; O=NAVER Corp.; CN=*.naver.com * start date: Mar 5 00:00:00 2025 GMT * expire date: Mar 17 23:59:59 2026 GMT * issuer: C=US; O=DigiCert Inc; CN=DigiCert TLS Hybrid ECC SHA384 2020 CA1 * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. * [CONN-1-0][CF-TCP] send(len=232) -> 232, err=0 > GET / HTTP/1.1 > Host: map.naver.com > Accept: */* > User-Agent:Mozilla/5.0 ((Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36; 360Spider SogouSpider > * [CONN-1-0][CF-TCP] recv(len=5) -> 5, err=0 * [CONN-1-0][CF-TCP] recv(len=442) -> 442, err=0 < HTTP/1.1 301 Moved Permanently < Date: Fri, 18 Apr 2025 06:33:02 GMT < content-type: text/plain; charset=utf-8 < content-length: 58 < keep-alive: timeout=3 < x-powered-by: Express < x-proxy-by: nautilus < x-bg-num: none < access-control-allow-origin: * < location: https://map.naver.com/p/ < vary: Accept < x-res-with: n3r < referrer-policy: unsafe-url < server: nfront < * Ignoring the response-body * Connection #1 to host map.naver.com left intact * Issue another request to this URL: 'https://map.naver.com/p/' * Found bundle for host: 0xbbea50 [serially] * Re-using existing connection #1 with host map.naver.com * [CONN-1-0][CF-TCP] send(len=234) -> 234, err=0 > GET /p/ HTTP/1.1 > Host: map.naver.com > Accept: */* > User-Agent:Mozilla/5.0 ((Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36; 360Spider SogouSpider > * [CONN-1-0][CF-TCP] recv(len=5) -> 5, err=0 * [CONN-1-0][CF-TCP] recv(len=1478) -> 1478, err=0 < HTTP/1.1 200 OK < Date: Fri, 18 Apr 2025 06:33:02 GMT < content-type: text/html < content-length: 1465 < keep-alive: timeout=3 < vary: Accept-Encoding < last-modified: Tue, 15 Apr 2025 06:13:06 GMT < etag: "67fdf8f2-5b9" < strict-transport-security: max-age=0; includeSubDomains < accept-ranges: bytes < referrer-policy: unsafe-url < server: nfront < <!doctype html><html lang="ko"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta property="og:type" content="website"/><meta name="referrer" content="always"/><title>네이버 지도</title><base href="/p/"/><link rel="search" type="application/opensearchdescription+xml" href="assets/opensearch.xml" title="네이버지도"/><link rel="manifest" href="assets/manifest.json" crossorigin="use-credentials"/><link rel="shortcut icon" type="image/x-icon" href="assets/icons/favicon.ico"/><link rel="apple-touch-icon" sizes="180x180" href="assets/icons/apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="assets/icons/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="16x16" href="assets/icons/favicon-16x16.png"/><meta name="msapplication-TileColor" content="#03c75b"/><meta name="theme-color" content="#ffffff"/></head><body><div id="root"></div><div id="report-screen-shot"></div><script defer="defer" src="https://maps-service.pstatic.* [CONN-1-0][CF-TCP] recv(len=5) -> 5, err=0 * [CONN-1-0][CF-TCP] recv(len=376) -> 376, err=0 * Connection #1 to host map.naver.com left intact net/pcweb_navermap_v5/250415-fc07f9e/runtime.fc07f9e.js"></script><script defer="defer" src="https://maps-service.pstatic.net/pcweb_navermap_v5/250415-fc07f9e/vendor.fc07f9e.js"></script><script defer="defer" src="https://maps-service.pstatic.net/pcweb_navermap_v5/250415-fc07f9e/browserChecker.js"></script><script defer="defer" src="https://maps-service.pstatic.net/pcweb_navermap_v5/250415-fc07f9e/main.fc07f9e.js"></script></body></html>
浙公网安备 33010602011771号