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...” 这一行。

  • 如果是 OpenSSLwolfSSL:则输出方式不同,不一定有那一行。


✅ 想强制查看 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(模拟蜘蛛爬虫)

请求流程大致如下:

  1. http://map.naver.com 发起请求(明文 HTTP 80 端口)

  2. 收到 302 跳转到 https://map.naver.com/

  3. 重新用 HTTPS 建立连接(443 端口)

  4. TLS 握手开始

  5. TLS 握手完成(协商出密钥、对称加密方式等)

  6. 发送 GET 请求(加密的)

  7. 收到 301 跳转到 https://map.naver.com/p/

  8. 跟随跳转,再次发起 GET 请求

  9. 返回 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 重定向流程

你经历了两次重定向:

  1. HTTP 302 → https://map.naver.com/

  2. 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?

建议你:

  1. 用 Wireshark 抓包,观察 TLS 报文内容(看 TLS Record Layer)

  2. 使用 openssl 验证服务器证书链:

    openssl s_client -connect map.naver.com:443
    
  3. 用 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>

  

posted on 2025-04-18 14:49  吃草的青蛙  阅读(112)  评论(0)    收藏  举报

导航