📘 第八章 确认访问用户身份的认证
📄 一句话概括

证书是「持有」,密码是「知识」,两类叠起来才叫双因素。 Demo 里四种组合只有一种能进,两种失败还落在不同层。

📝 本节和前面几节的关系

上一节只有一把锁,这一节加第二把。 要注意的是——两把锁必须是不同性质的,否则只是同一把锁拧两次。

一、四种组合,只有一种能进

Demo 里两层检查:TLS 层要客户端证书,应用层要账号密码。四种组合的结果: | 客户端证书 | 账号密码 | 结果 | |:---:|:---:|---| | 无 | 无 | 握手就断 | | 无 | 有 | 握手就断 | | 有 | 无 | TLS 过了,应用层 401 | | 有 | 有 | 通过,收到 135 字节 | 前两行一样:没有证书,密码再对也没用——因为根本没机会发出去。 第三行是这次实测最有意思的一行:TLS 谈成了,客户端以为自己连上了,结果被应用层挡在 401。 这说明两层是串联的,不是并联。任何一层不过,整个流程就停。

二、为什么必须是两类

证书属于「持有」:你得有那个私钥文件。密码属于「知识」:你得记住那串字符。 两类同时被攻破的概率远小于单独一类:偷了电脑的人未必知道密码;猜到密码的人未必拿得到私钥文件。 这就是双因素的全部逻辑。 反例:密码加「密保问题」,两个都是知识,攻破一个的思路往往能攻破另一个,所以不算双因素。 密码加短信验证码才算——手机是「持有」。 再往上一层是「无密码」:只靠持有(比如 passkey,私钥存在设备的安全芯片里,用生物特征解锁)。 它本质上还是双因素——持有设备加特征解锁,只是把「知识」那一项去掉了。

三、代价换来了什么

代价是复杂度:用户要装证书、选证书、证书过期要换。所以这套组合基本只出现在内部系统和高价值后台。 换来的是抗钓鱼。 密码可以被骗走,验证码可以被转发,但客户端证书的私钥不会离开设备——钓鱼网站拿不到它, 因为它只在跟真服务端握手时才会用到。 这一点在今天的攻防里越来越重要:验证码中间人攻击(把验证码实时转发给真站点)已经做得很成熟, 而客户端证书对这类攻击天然免疫。

四、动手 Demo:四种组合,两条不同的失败路径

同一个服务端,TLS 层要求客户端证书,应用层要求 Basic 凭据。 客户端按「有没有证书」「有没有密码」四种组合各试一次,看失败发生在哪一层。

# TLS 层:要证书
sctx.verify_mode = ssl.CERT_REQUIRED
sctx.load_verify_locations(ca_p)

# 应用层:要密码
cred = base64.b64encode(b'bozai:pa55word').decode('ascii')
extra = [(u'Authorization', u'Basic ' + cred)]

实跑输出:

--------------------------------------------------------------------
双因素:证书 + 密码,缺一个都不行
--------------------------------------------------------------------
  两层检查:TLS 层要客户端证书,应用层要账号密码。
  四种组合各试一次:
    证书=无 密码=无        失败:ConnectionResetError
    证书=无 密码=有        TLS 就断了:TLSV13_ALERT_CERTIFICATE_REQUIRED
    证书=有 密码=无        TLS 过了,但应用层要密码 → 401
    证书=有 密码=有        通过,收到 135 字节

  四种组合里只有最后一种能进。前两种失败的位置不同:
    没证书 → 卡在 TLS 握手,连 HTTP 都没开始;
    有证书没密码 → TLS 过了,卡在 401。

  这就是「双因素」的含义:两类**不同性质**的证据。
    证书属于「持有」——你得有那个文件;
    密码属于「知识」——你得记住那串字符。
  两类同时被攻破的概率远小于单独一类:偷了电脑的人未必知道密码,
  猜到密码的人未必拿得到私钥文件。

证书=无 密码=无:ConnectionResetError,握手就断。 证书=无 密码=有:同样 ConnectionResetError——密码根本没机会发。 证书=有 密码=无:TLS 通过,应用层回 401。这是唯一能看到 HTTP 状态码的失败。 证书=有 密码=有:通过,收到 135 字节。四行里只有这一行成功。

30 秒实验

  1. 把第二行的密码换成错的,看结果和「无证书」有没有区别。
  2. 把 CERT_REQUIRED 改成 CERT_OPTIONAL,重新跑四种组合。
  3. 想一想:短信验证码为什么算第二因素,而密保问题不算?

常见误区

  1. 「密码加密保问题是双因素」——两个都是知识。
  2. 「两层是并联关系,过一层就行」——是串联,任何一层不过都停。
  3. 「客户端证书也能被钓鱼」——私钥不离开设备,钓鱼拿不到。
自测三问(点开对答案) 1. 双因素里的「两因素」指什么? —— 两类不同性质的凭据,比如持有(证书)加知识(密码)。 2. 只有证书没有密码时,失败在哪一层? —— 应用层,回 401——TLS 已经通过了。 3. 为什么客户端证书抗钓鱼? —— 私钥不离开设备,只在跟真服务端握手时使用,钓鱼站拿不到。

这套方案很强,但很少有网站对公众用它。下一节用数字说明为什么。

相关笔记