← 中文资源

简体中文版本

协议降级攻击

降级攻击篡改握手消息,诱使协商双方选择弱于实际能力的协议版本或密码套件,如 TLS 1.0、出口级参数。

阅读英文原文

概念定义

协商本该选双方共同支持的最优项。主动攻击者编辑握手过程抹掉强选项:ClientHello 或 ServerHello 里的版本号被调低、密码列表被滤成弱项——双方于是“合法地”用了弱配置,且毫无察觉。

工作机制

TLS 1.2 及以下,重试回退是主要入口:客户端在伪造的失败后降到 1.1,就可能被钉死在那里;TLS_FALLBACK_SCSV 给重试打标记,诚实的服务器会中止。TLS 1.3 在 ServerHello 随机数里嵌入降级哨兵:支持 1.3 的服务器看到 1.2 协商即发出被篡改信号,1.3 客户端随之中止。

使用场景

自管重试策略的客户端 SDK、生命周期长的嵌入式设备、以及一切 TLS 终结代理。全面禁用废弃版本与出口套件,再用遥测核实实际协商到的版本。

常见误区

证书校验认证的是身份,不是实际协商的协议版本;服务器单侧禁旧版不够,攻击打的是客户端协商——回退标记与客户端策略才闭环。HSTS 与证书固定也不能替代协议策略。中间盒强制 1.2 会让降级面在 1.3 端点间依然存活;配置漂移会悄悄重开遗留套件——外部扫描必须排期。

代码示例

function shiftLetters(text, offset) {
  if (typeof text !== "string") throw new TypeError("text must be a string");
  if (!Number.isInteger(offset)) throw new TypeError("offset must be an integer");
  const normalized = ((offset % 26) + 26) % 26;
  return text.replace(/[a-z]/gi, (char) => {
    const base = char <= "Z" ? 65 : 97;
    return String.fromCharCode(((char.charCodeAt(0) - base + normalized) % 26) + base);
  });
}

export function caesarCipher(text, offset) {
  return shiftLetters(text, offset);
}

export function rot13(text) {
  return shiftLetters(text, 13);
}
package main

import (
	"crypto/sha256"
	"crypto/subtle"
	"fmt"
)

func ConstantTimeEqual(a, b string) bool {
	left := sha256.Sum256([]byte(a))
	right := sha256.Sum256([]byte(b))
	return subtle.ConstantTimeCompare(left[:], right[:]) == 1
}

func main() {
	secret := "s3cr3t-token"
	fmt.Println(ConstantTimeEqual(secret, "s3cr3t-token"))
	fmt.Println(ConstantTimeEqual(secret, "s3cr3t-tokeX"))
	fmt.Println(ConstantTimeEqual(secret, "short"))
}