ESNI 和ECH的前世今生

news2025/1/18 7:02:55

这边文章中提到过虽然 TLS 能够加密整个通信过程,但是在协商的过程中依旧有很多隐私敏感的参数不得不以明文方式传输,其中最为重要且棘手的就是将要访问的域名,即 SNI(Server Name Indication)。同时还有用于告知客户端可用的应用层协议的 ALPN 拓展,泄露这个会导致攻击者知道服务器所支持的服务以及连接的用途。

 之所以会暴露如此重要的内容,并不是设计时的失误,而是因为加密该内容会使得许多服务器无法正常工作。通常来说,一台服务器往往会提供许多服务,小到用 nginx 反向代理数个服务,大到 CDN 服务器同时为无数网站提供服务,而因为域名的不同,证书也不相同。那么当客户端访问服务的时候必须指明 SNI,服务器才知道应该返回哪个证书,但客户端收到证书前又没有办法加密,就陷入了一个先有鸡还是先有蛋的尴尬境地。ESNI 以及其后继 ECH 就是被设计出来弥补这一问题。

1、Encrypted SNI

ESNI(Encrypted SNI)正如其名,其设计的目标就是为了加密 SNI,是最先为解决这一问题提出的一个 TLS 拓展。虽然这一方案即将被废弃,但对于了解其后继者 ECH 有着极大的帮助。

ESNI 为了能够让客户端获得密钥发送密文,依赖于另一个服务 DNS 来分发密钥。客户端在使用 ESNI 连接服务器之前,会在常规的请求网站 IP 的 A/AAAA 请求上再进行一次 TXT 的请求以获得 ESNI 的公钥(实际是用 BASE64 编码后的公钥以及类似加密算法之类的参数),如下是请求本博客的结果:

$ dig _esni.crypto.dance TXT +short
"/wGuNThxACQAHQAgXzyda0XSJRQWzDG7lk/r01r1ZQy+MdNxKg/mAqSnt0EAAhMBAQQAAAAAX67XsAAAAABftsCwAAA="

补充:关于dig命令见linux dig 命令 - sparkdev - 博客园

客户端会将加密后的 SNI 以拓展的形式发送。服务器收到请求后就会用对应的私钥解密,并用解密后得到 SNI 进行后续的操作。解密失败则终止连接。

不过 DNS 请求本身是明文的,依旧存在风险,所以部署 ESNI 还需要引入 DoH(DNS over HTTPS)。DoH 除了保证可以加密传输公钥之外,还有一个重要的点就是可以认证 DoH 服务器,保证访问到的是正确的服务器,而非是(攻击者精心准备的)本地网络缓存,从而避免了本地缓存返回一个空的 TXT 记录以阻止客户端使用 ESNI 或者返回一个攻击者控制的密钥使得客户端使用了错误的公钥加密。但这一方法仍然存在问题:

  • 首先就是密钥的分发,Cloudflare 在部署时每个小时都会轮换密钥,这样可以降低密钥泄露带来的损失,但是 DNS 有缓存的机制,客户端很可能获得的是过时的密钥,此时客户端就无法用 ESNI 继续进行连接。
  • 其次是对网站的 DNS 请求可能返回有几个 IP 地址,每个地址分别代表了不同的 CDN 服务器,然而 ESNI 的 TXT 记录只有一个,可能会将该密钥发送给了错误的服务器导致握手失败。

2、Encrypted Client Hello

ECH(Encrypted Client Hello)出现的目标就是就是为了克服 ESNI 的缺陷,同时也正如其名,ECH 有着更大的野心,不单单加密 SNI,而是要加密整个 Client Hello。

ECH是 TLS 1.3 的草案扩展,它使客户端能够在 TLS 握手中加密其 client_hello,以防止泄露在正常 TLS 握手期间以明文形式发送的敏感元数据。ECH 最初被提议为 ESNI(加密服务器名称指示),因为服务器名称指示是握手过程中被动观察者可见的敏感字段之一,但后来更名,因为它涵盖了整个 Client Hello。 ECH 使用 HPKE(混合公钥加密)来导出共享密钥并加密 client_hello。

ECH 同样采用 DoH 进行密钥的分发,但是在分发过程上进行了改进。相较于 ESNI 服务器解密失败后终止连接,ECH 服务器会提供给客户端一个公钥供客户端重试连接,以期可以完成握手。

那么问题来了,解密失败服务器还是不知道 SNI 是多少,那么怎么返回公钥呢?

实际上 ECH 的 Client Hello 分为了两个部分,分别称为 ClientHelloOuter 和 ClientHelloInner。

  • ClientHelloOuter 同普通的 Client Hello 消息一样,但删除了所有敏感元数据,只有连接必要的握手参数。
  • ClientHelloInner:包含敏感信息,并使用 HPKE 加密,然后作为 ECH 扩展跟在 ClientHelloOuter 后面。

客户端发送外部问候,服务器使用 ECH 进行接收,并使用其 HPKE 密钥解密内部问候。

而服务器这边,握手实际上由 ECH 服务提供者来完成(称为 client-facing server)而非域名对应的背后的服务,由它来通知客户端解密是否成功以及发送正确的 ECH 公钥。

补充:ECH在wolfssl上已经支持了,见:Encrypted Client Hello (ECH) now supported in wolfSSL - wolfSSL

总结

ECH 是将会是 TLS 的又一次重大升级,这一次使得每次连接除了其发起者和接收者之外,没有人能够知道访问的是什么,有助于进一步保护用户隐私。尽管 ECH 还是一项进行中的工作,但随着工作的继续,显然我们离更安全的互联网又近了一步。

 

参考文档:ESNI 与 ECH 的前世今生 - ZingLix Blog

以下是Good-bye ESNI, hello ECH ! 译文

原文:https://blog.cloudflare.com/encrypted-client-hello/

现代 Internet 上的大多数通信都是加密的,以确保其内容仅对端点(即客户端和服务器)是可理解的。然而,加密需要密钥,因此端点必须就加密密钥达成一致,而不会将密钥透露给潜在的攻击者。这项任务使用最广泛的加密协议称为密钥交换,是传输层安全 (TLS) 握手。

在本文中,我们将深入探讨 Encrypted Client Hello (ECH),它是 TLS 的新扩展,有望显着增强这一关键 Internet 协议的隐私性。今天,TLS 连接的许多隐私敏感参数都是以明文方式协商的。这为网络观察者留下了大量可用的元数据,包括端点的身份、它们如何使用连接等。

ECH 对完整的握手进行加密,以便此元数据保密。至关重要的是,这通过保护服务器名称指示 (SNI) 免受网络上的窃听者的侵害来解决长期存在的隐私泄露问题。加密 SNI 很重要,因为它是给定客户端正在与哪个服务器通信的最清晰信号。然而,也许更重要的是,ECH 还为向 TLS 添加未来的安全功能和性能增强,同时最大限度地减少它们对最终用户隐私的影响奠定了基础。

ECH 是在 IETF 的推动下,学术界和技术行业领导者之间密切合​​作的产物,包括 Cloudflare、我们在 Fastly 和 Mozilla 的朋友(他们都是该标准的共同作者的附属机构)以及许多其他人。此功能代表了对 TLS 协议的重大升级,该协议建立在最先进的技术之上,例如 DNS-over-HTTPS,这些技术现在才逐渐成熟。因此,该协议尚未准备好进行互联网规模的部署。本文旨在作为通向完全握手加密的路标。

1、Background

TLS 的故事就是互联网的故事。随着我们对 Internet 的依赖程度不断增加,该协议也在不断发展以应对不断变化的操作要求、用例和威胁模型。客户端和服务器不只是交换密钥。他们协商各种各样的特性和参数:密钥交换的确切方法;加密算法;谁进行了身份验证以及如何进行身份验证;握手后使用哪个应用层协议;还有很多很多。所有这些参数都以某种方式影响通信通道的安全属性。

SNI 是影响通道安全性的参数的主要示例。客户端使用 SNI 扩展来向服务器指示它想要访问的网站。这对于现代互联网来说是必不可少的,因为现在许多原始服务器都位于单个 TLS 运营商后面很常见。在此设置中,操作员使用 SNI 来确定谁将对连接进行身份验证:没有它,就无法知道向客户端提供哪个 TLS 证书(域名不同,证书也不同)。问题在于 SNI 会向网络泄露客户端想要连接的原始服务器的身份,从而可能允许窃听者推断出有关其通信的大量信息。 (当然,网络观察者还有其他方法可以识别来源——例如,来源的 IP 地址。但是与同一 IP 地址上的其他来源共置使得使用此度量来确定来源比它只是简单地检查 SNI。)

虽然保护 SNI 是 ECH 的推动力,但它绝不是客户端和服务器协商的唯一隐私敏感握手参数。另一个是 ALPN 扩展,它用于在建立 TLS 连接后决定使用哪个应用层协议。客户端发送它支持的应用程序列表——无论是 HTTPS、电子邮件、即时消息,还是使用 TLS 进行传输安全的无数其他应用程序——服务器从该列表中选择一个,并将其选择发送给客户端。通过这样做,客户端和服务器向网络泄露了一个明确的信号,表明它们的能力以及连接可能用于什么。

有些功能对隐私非常敏感,以至于将它们包含在握手中是行不通的。已经提出的一个想法是使用password-authenticated key-exchange (PAKE)替换 TLS 核心的密钥交换。这将允许基于密码的身份验证与基于证书的身份验证一起使用(或代替),从而使 TLS 更加健壮并适用于更广泛的应用程序。这里的隐私问题类似于 SNI:服务器通常将唯一标识符关联到每个客户端(例如,用户名或电子邮件地址),用于检索客户端的凭据;并且客户端必须以某种方式在握手过程中将此身份传递给服务器。如果以明文形式发送,那么任何网络观察者都可以轻松访问此个人身份信息。

解决所有这些隐私泄露的一个必要因素是对握手加密,即除了应用程序数据之外,还对握手消息进行加密。听起来很简单,但这个解决方案带来了另一个问题:毕竟,如果握手本身就是交换密钥的一种方式,那么客户端和服务器如何选择加密密钥?(先有鸡、先有蛋?)当然,有些参数必须以明文形式发送,因此 ECH 的目标是加密所有握手参数,除了那些对完成密钥交换必不可少的参数。

2、Handshake encryption in TLS

为了理解 ECH 和支撑它的设计决策,稍微了解一下 TLS 中握手加密的历史会有所帮助。

在最新版本 TLS 1.3 之前,TLS 根本没有握手加密。在 2013 年斯诺登事件曝光后,IETF 社区(互联网工程任务组 Internet Engineering Task Force)开始考虑如何应对大规模监控对开放互联网造成的威胁。当 2014 年开始标准化 TLS 1.3 的过程时,其设计目标之一是尽可能多地加密握手。不幸的是,最终标准没有完全握手加密,包括 SNI 在内的几个参数仍然以明文形式发送。让我们仔细看看为什么。

TLS 1.3 协议流程如上图所示。只要客户端和服务器计算出新的共享密钥,握手加密就会开始。为此,客户端在其 ClientHello 消息中发送一个密钥共享,而服务器在其 ServerHello 中使用自己的密钥共享进行响应。交换了这些共享后,客户端和服务器可以导出共享秘密。每个后续的握手消息都使用从共享秘密派生的握手流量密钥进行加密。应用程序数据使用不同的密钥加密,称为应用程序流量密钥,它也是从共享秘密派生的。这些派生密钥具有不同的安全属性:为了强调这一点,它们用不同的颜色表示。

加密的第一个握手消息是服务器的 EncryptedExtensions。此消息的目的是保护服务器的敏感握手参数,包括服务器的 ALPN 扩展,其中包含从客户端的 ALPN 列表中选择的应用程序。密钥交换参数在 ClientHello 和 ServerHello 中未加密发送。

客户端的所有握手参数,无论是否敏感,都在 ClientHello 中发送。查看图 1,您可能会想到重新处理握手的方法,以便可以对其中一些进行加密,但可能会以额外的延迟为代价(即,通过网络进行更多往返)。然而,像 SNI 这样的扩展会产生一种“先有鸡还是先有蛋”的问题。

客户端不会加密任何东西,直到它验证了服务器的身份(这是 Certificate 和 CertificateVerify 消息的工作)并且服务器已经确认它知道共享秘密(Finished 消息的工作)。这些措施可确保密钥交换经过身份验证,从而防止中间人 (MITM) 攻击,在这种攻击中,对手以允许其解密客户端发送的消息的方式向客户端冒充服务器。因为服务器选择证书需要SNI,所以需要在密钥交换认证之前传输。

通常,只有在客户端和服务器已经共享加密密钥的情况下,才能确保用于身份验证的握手参数的机密性。但是这个密钥可能来自哪里?

TLS 1.3 早期的全握手加密。有趣的是,全握手加密曾被提议作为 TLS 1.3 的核心特性。在该协议的早期版本(draft-10,大约 2015 年)中,服务器会在握手期间为客户端提供一个长期有效的公钥,客户端将在随后的握手中使用该公钥进行加密。 (这个设计来自一个叫做 OPTLS 的协议,它又是从最初的 QUIC 提议中借用的。)被称为“0-RTT”,这个模式的主要目的是允许客户端在完成握手之前开始发送应用程序数据.此外,它还允许客户端对 ClientHello 之后的第一次握手消息进行加密,包括它自己的 EncryptedExtensions,这可能已用于保护客户端的敏感握手参数。

终此功能未包含在最终标准(RFC 8446,2018 年发布)中,主要是因为其增加的复杂性超过了它的实用性。特别是,它不会保护客户端获知服务器公钥的初始握手。初始握手的服务器身份验证所需的参数(如 SNI)仍将以明文形式传输。

尽管如此,该方案作为其他握手加密机制(如 ECH)的先驱而引人注目,它使用公钥加密来保护敏感的 ClientHello 参数。这些机制必须解决的主要问题是密钥分发。

3、Before ECH there was (and is!) ESNI

ECH 的直接前身是加密 SNI (ESNI) 扩展。顾名思义,ESNI 的目标是为 SNI 提供机密性。为此,客户端将在服务器的公钥下加密其 SNI 扩展并将密文发送到服务器。服务器将尝试使用与其公钥相对应的密钥来解密密文。如果解密成功,则服务器将使用解密的 SNI 继续连接。否则,它将简单地中止握手。这个简单协议的高级流程如图 2 所示。

对于密钥分发,ESNI 依赖于另一个关键协议:域名服务 (DNS)。为了使用 ESNI 连接到网站,客户端将在其标准 A/AAAA 上使用 ESNI 公钥查询 TXT 记录请求。例如,要获取 crypto.dance 的密钥,客户端将请求 _esni.crypto.dance 的 TXT 记录:

$ dig _esni.crypto.dance TXT +short "/wGuNThxACQAHQAgXzyda0XSJRQWzDG7lk/r01r1ZQy+MdNxKg/mAqSnt0EAAhMBAQQAAAAAX67XsAAAAABftsCwAAA="

base64 编码的 blob 包含 ESNI 公钥和相关参数,例如加密算法。

但是,如果我们只是要通过明文 DNS 查询将服务器名称泄露给网络观察者,那么加密 SNI 有什么意义呢?随着 DNS-over-HTTPS (DoH) 的引入,以这种方式部署 ESNI 变得可行,它可以对提供 DoH 服务的解析器的 DNS 查询进行加密(1.1.1.1 是此类服务的一个示例。)。 DoH 的另一个重要特性是它提供了一个经过身份验证的通道,用于将 ESNI 公钥从 DoH 服务器传输到客户端。这可以防止源自客户端本地网络的缓存中毒攻击:在没有 DoH 的情况下,本地攻击者可以通过返回空 TXT 记录来阻止客户端提供 ESNI 扩展,或者强制客户端使用带有密钥的 ESNI控制。

尽管 ESNI 向前迈出了重要一步,但它还没有达到我们实现完全握手加密的目标。除了不完整——它只保护 SNI——它还容易受到一些复杂的攻击,这些攻击虽然很难实现,但指出了协议设计中需要解决的理论弱点。

ESNI 于 2018 年由 Cloudflare 部署并由 Firefox 在选择加入的基础上启用,这种体验暴露了依赖 DNS 进行密钥分发的一些挑战。 Cloudflare 每小时轮换一次其 ESNI 密钥,以便在密钥遭到破坏时最大限度地减少附带损害。 DNS 工件有时会缓存更长时间,其结果是客户端很有可能拥有过时的公钥。虽然 Cloudflare 的 ESNI 服务在一定程度上容忍了这一点,但每个密钥最终都必须过期。 ESNI 协议未解决的问题是,如果解密失败且无法通过 DNS 或其他方式访问当前公钥,客户端应如何处理。

依赖 DNS 进行密钥分发的另一个问题是,多个端点可能对同一源服务器具有权威性,但具有不同的功能。例如,对“example.com”的 A 记录的请求可能会返回两个不同 IP 地址之一,每个 IP 地址由不同的 CDN 运营。 “_esni.example.com”的 TXT 记录将包含这些 CDN 之一的公钥,但肯定不会包含两者。 DNS 协议不提供一种将对应于同一端点的资源记录自动绑定在一起的方法。特别是,客户端可能会无意中向不支持它的端点提供 ESNI 扩展,从而导致握手失败。解决此问题需要更改 DNS 协议。 (更多内容见下文。)

ESNI 的未来。在下一节中,我们将描述 ECH 规范以及它如何解决 ESNI 的缺点。然而,尽管存在局限性,但 ESNI 提供的实际隐私优势非常重要。 Cloudflare 打算继续支持 ESNI,直到 ECH 准备好投入生产。

4、The ins and outs of ECH(ECH的来龙去脉)

ECH 的目标是加密整个 ClientHello,从而通过保护所有隐私敏感的握手参数来弥补 TLS 1.3 和 ESNI 中留下的差距。与 ESNI 类似,该协议使用通过 DNS 分发并使用 DoH 获得的公钥在客户端的首次飞行期间进行加密。但 ECH 对密钥分发进行了改进:

  • 使该协议对 DNS 缓存不一致的情况更加稳健。
  • 如果解密失败,ESNI 服务器会中止连接,而 ECH 服务器会尝试完成握手并为客户端提供可用于重试连接的公钥。

但是,如果服务器无法解密 ClientHello,它如何完成握手呢?如图 3 所示,ECH 协议实际上涉及两个 ClientHello 消息:ClientHelloOuter,它像往常一样以明文形式发送;和 ClientHelloInner,它被加密并作为 ClientHelloOuter 的扩展发送。服务器仅使用这些 ClientHellos 之一完成握手:如果解密成功,则继续使用 ClientHelloInner;否则,它将继续处理 ClientHelloOuter。

ClientHelloInner 由客户端想要用于连接的握手参数组成。这包括敏感值,例如它想要到达的源服务器的 SNI(在 ECH 术语中称为后端服务器)、ALPN 列表等。 ClientHelloOuter 虽然也是一个成熟的 ClientHello 消息,但不用于预期的连接。相反,握手由 ECH 服务提供商本身(称为面向客户端的服务器)完成,向客户端发出信号,告知其由于解密失败而无法到达预期目的地。在这种情况下,服务提供商还会发送正确的 ECH 公钥,客户端可以使用该公钥重试握手,从而“更正”客户端的配置。 (这种机制类似于服务器在 TLS 1.3 早期为 0-RTT 模式分发公钥的方式。)

至少,两个 ClientHellos 都必须包含服务器验证密钥交换所需的握手参数。特别是,虽然 ClientHelloInner 包含真实的 SNI,但 ClientHelloOuter 还包含一个 SNI 值,客户端希望在 ECH 解密失败的情况下验证该值(即,面向客户端的服务器)。如果使用 ClientHelloOuter 建立连接,则客户端应立即中止连接并使用服务器提供的公钥重试握手。客户端不必在 ClientHelloOuter 中指定 ALPN 列表,也不必指定用于指导握手后行为的任何其他扩展。所有这些参数都被加密的 ClientHelloInner 封装。

这种设计解决了 - 我认为非常优雅 - 早期机制遇到的安全部署握手加密的大部分挑战。重要的是,ECH 的设计并不是在真空中构思出来的。该协议反映了 IETF 社区的不同观点,其发展与对 ECH 的成功至关重要的其他 IETF 标准相吻合。

  • 第一个是重要的新 DNS 功能,称为  HTTPS resource record type.。在较高级别上,此记录类型旨在允许对同一域名具有权威性的多个 HTTPS 端点为 TLS 通告不同的功能。这使得依赖 DNS 进行密钥分发成为可能,解决了初始 ESNI 部署所发现的部署挑战之一。要深入了解这种新记录类型及其对 Internet 更广泛的意义,请查看 Alessandro Ghedini 最近关于该主题的博客文章。
  • 第二个是 CFRG 的混合公钥加密 (HPKE) 标准,它指定了一个可扩展的框架,用于构建适用于各种应用程序的公钥加密方案。特别是,ECH 将其握手加密机制的所有细节都委托给了 HPKE,从而使规范更加简单和易于分析。 (顺便说一下,HPKE 也是 Oblivious DNS-over-HTTPS 的主要成分之一。)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/142338.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

javaEE高阶---MyBatis

一 : 什么是MyBatis MyBatis是更简单完成程序和数据库交互的工具,也就是更简单的操作和读取数据库的工具.MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 去除了几乎所有的 JDBC 代码以及设置参数和获取结果集的动作 . MyBatis …

[oeasy]python0037_终端_terminal_电传打字机_tty_shell_控制台_console_发展历史

换行回车 回忆上次内容 换行 和 回车 是两回事 换行 对应字节0x0ALine-Feed 水平 不动垂直 向上喂纸 所以是 feed 回车 对应字节0x0DCarriage-Return 垂直 不动水平 回到纸张左侧 可移动的打印头 运输字符 的 装置 (Carriage)回到 行首 所以是 Return tty、terminal、shell、…

【视觉SLAM】DM-VIO: Delayed Marginalization Visual-Inertial Odometry

L. v. Stumberg and D. Cremers, “DM-VIO: Delayed Marginalization Visual-Inertial Odometry,” in IEEE Robotics and Automation Letters, vol. 7, no. 2, pp. 1408-1415, April 2022, doi: 10.1109/LRA.2021.3140129. 论文阅读方法:Title,Abstract…

百趣代谢组学文献分享:学科交叉研究,微生物回收重金属机制研究

发表期刊:Environment International 影响因子:7.297 发表时间:2019年 合作单位:福建农林大学 百趣代谢组学文献分享,该文章是BIOTREE协助客户2019年发表在Environment International上的关于微生物回收重金属机制研…

Tomcat的Connector启动过程分析

一. 前言 前面分析了tomcat的整体架构和tomcat的启动过程,在分析启动过程的时候只讲了整体的启动过程,本篇来重点分析一下tomcat的Connector(连接器)组件的启动过程。 二.从Connector的构造开始 那么org.apache.catalina.connector.Connector是在什么…

文献学习06_利用句法指示符和句子上下文加强关系抽取

论文信息 Subjects: Computation and Language (cs.CL) (1)题目:Enhancing Relation Extraction Using Syntactic Indicators and Sentential Contexts (利用句法指示符和句子上下文加强关系抽取) (2&…

论文精读:RPM-Net: Robust Point Matching using Learned Features

论文地址:https://arxiv.org/pdf/2003.13479.pdf 点云配准任务 点云配准可以当做一个基础的上游任务,根据从不同视角下获取的点云数据配准为完整的点云数据,下游任务众多 基本任务:求一个变换矩阵,使得两个具有未知点的点云数据重合。 刚性与非刚性: 刚性配准:旋转和平…

Leetcode 121买卖股票的最佳时机

题目描述: 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔…

solr集群配置(使用solr自带的Jetty实现集群配置)

看了很多的资料发现基本集群搭建都是通过tomcat的方式实现的,但是在高版本的solr中,可以通过solr自带的jetty实现集群的搭建 准备 1.虚拟机安装linux 2.安装jdk 3.下载solr并解压 步骤 1.进入到解压后solr的bin目录下,并执行 ./solr -e clo…

赛狐ERP | 如何高效管理亚马逊广告!用这款亚马逊ERP就够了!

亚马逊的广告管理是是每一位亚马逊运营的必修课,除自然流量外,广告来带的流量与转化占比都极高,广告做活了,就是打虎上山;广告搞砸了,就是骑虎难下:不开广告吧没有流量卖不动、开了广告吧财务账…

#B. 部落联盟

一,题目Description在草原上有N个部落,每个部落都有其坐标(xi,yi)每个部落都有个武力值,可正可负由于部落间只能通过马匹来传递信息于是只有当两个部落间的距离为1的时候,两个部落才有可能进行联系,距离计算公式为abs(xi-xj)abs(y…

人生的喜悦、不快与成长,都在那一篇篇的文字中得到记录 | 2022 年终总结

又是一年的总结,不知道自己今年又该写点什么。但提笔总是好的,也算对今年的一个交代和对未来的一份期许。窗外的阳光正好,对面楼的敲打声叮叮咚咚,窗台上的两只猫睡得依旧奔放和舒适。这样一个看似美好的下午,一个平凡…

Internet Download Manager2023最好用的HTTP下载神器

Internet Download Manager 介绍2023最佳下载利器。Internet Download Manager (简称IDM) 是一款Windows 平台功能强大的多线程下载工具,国外非常受欢迎。支持断点续传,支持嗅探视频音频,接管所有浏览器,具有站点抓取、批量下载队…

机器学习100天(二十六):026 k近邻分类算法-理论

机器学习100天,今天讲的是:K 近邻分类算法-理论。 《机器学习100天》完整目录:目录 一、什么是 K 近邻算法 K 近邻算法也叫 KNN(k-Nearest Neighbor)算法,它是一个比较成熟也是最简单的机器学习算法之一。K 近邻分类算法的思路是:如果一个样本在特征空间中与 K 个实例最…

FastAPI集成Socket.io坑点汇集和技术选型

背景 单纯的 websocket 通信方式存在大量的辅助性的工作需要处理,例如心跳机制、粘包处理、协议规范等,所以直接使用 websocket 开发,等于重复造轮子,毫无价值,而 socket.io 整理了一整套规范和机制,可以满…

DSP-频域中的离散时间信号

目录 连续和离散时间傅里叶变换: 四种常用的傅立叶变换: 连续时间傅立叶变换(FT): 离散时间傅里叶变换(DTFT): 对称关系: DTFT的收敛条件: 常用DTFT对: DTFT的性质: 线性: 时间反转: 时移: 频移&#xff1a…

鲁大师2022牛角尖颁奖盛典落幕,各大硬件厂商齐聚襄阳

1月4日,鲁大师2022年度牛角尖颁奖晚会在湖北襄阳成功举办。 鲁大师的”牛角尖”奖是由过去一年上亿用户通过鲁大师测试得到的真实数据,以及鲁大师实验室通过专业的测试规范共同缔造的硬件奖项。颁发给的都是各大PC、手机、电动车领域最优秀、最顶尖的产…

【自学Python】Python HelloWorld

Windows Python HelloWorld Windows Python HelloWorld 教程 使用记事本,新建一个 helloworld.py 文件,输入以下内容: print(嗨客网(www.haicoder.net))打开命令行,进入到 helloworld.py 文件所在目录,输入以下命令…

干货 | 移动端App自动化之App控件定位

客户端的页面通过 XML 来实现 UI 的布局,页面的 UI 布局作为一个树形结构,而树叶被定义为节点。这里的节点也就对应了我们要定位的元素,节点的上级节点,定义了元素的布局结构。在 XML 布局中可以使用 XPath 进行节点的定位。App的…

Spring项目

1.创建一个Java项目 名字为Test_SM_1 2.导包 Java项目,用快捷方式的方法导入 web项目用复制的方式 一共8个包,前两个是通用jar包,Spring相关的jar包有4个,mybatis的jar包有1个,mysql的jar包连接数据库 3. 复原一个MyB…