当前位置: 首页 > news >正文

ARMV8安全特性:Pointer Authentication

文章目录

  • 前言
  • 一、Introduction
  • 二、Problem Definition
  • 三、Pointer Authentication
    • 3.1 Instructions
    • 3.2 Cryptography
    • 3.3 Key Management
  • 四、Sample Use Cases
    • 4.1 Software Stack Protection
    • 4.2 Control Flow Integrity (CFI)
    • 4.3 Binding Pointers to Addresses
  • 五、Security Properties
    • 5.1 Arbitrary memory read
    • 5.2 Arbitrary memory write
    • 5.3 Guessing and forging PAC values
    • 5.4 Pointer substitution attacks
    • 5.5 Key management concerns and key reuse attacks
    • 5.6 Interpreters and Just-in-Time Compilation (JIT)
  • 六、Conclusion

前言

本文来自于https://www.qualcomm.com/content/dam/qcomm-martech/dm-assets/documents/pointer-auth-v7.pdf的翻译。

一、Introduction

ARMv8.3-A是ARMv8-A架构的2016年新增内容。这些新增内容包括指针认证指令:“与指针认证相关的增强安全机制”。非常令人兴奋的是,这项技术通过与ARM及其合作伙伴的讨论和贡献进一步完善和扩展,并作为新的指针认证指令纳入到架构中。

ARM引入的指针认证方案是一种软件安全原语,可以使攻击者在未被检测到的情况下更难修改内存中的受保护指针。在本文档中,我们将提供关于指针认证机制的更多详细信息,进行安全分析,并讨论使用指针认证原语实施某些软件安全对策,例如堆栈保护和控制流完整性。

二、Problem Definition

软件安全中常见的一个问题是内存损坏漏洞,例如缓冲区溢出。这些漏洞通常通过覆盖内存中的控制数据(函数指针和返回地址)来利用,将代码执行重定向到由攻击者控制的位置。有三种常见的方式来防御内存损坏利用:
(1)将敏感数据和指针放入只读内存以防止损坏:对于静态函数指针表和其他敏感数据,这种方式非常有效。但仍需要确保对这些只读表的任何指针也经过验证或受到保护。不幸的是,对于动态指针,如堆栈上的返回地址或包含函数指针的动态分配对象,这种方式不起作用。

(2)在使用指针之前通过验证来检测损坏:这是软件堆栈保护(SSP)的工作原理。控制流完整性(CFI)和其他返回导向编程(ROP)的缓解措施,例如检查跳转/返回目标的各种属性,也属于这个类别。

(3)加大找到目标的难度:这可以通过某种形式的随机化来实现。随机化是一种良好的通用防御措施,使得可靠地利用系统变得更加困难。这个类别中的对策范围从随机化堆栈/堆(使得更难找到要破坏的指针),到完全的地址空间布局随机化(ASLR)(使得更难确定跳转的位置)。需要注意的是,一些检测对策措施(如堆栈保护)也需要不可预测性(例如,随机的堆栈保护标志)才能发挥作用。

这些技术是互补的,大多数现代对抗设计都使用它们的组合。

高通技术公司的产品安全工作之一是将软件安全对策引入其平台。这不仅涵盖运行主操作系统的应用处理器,还包括用于引导加载程序、调制解调器、WiFi和DSP等外设的镜像,以及用于虚拟化程序和TrustZone等其他执行环境。这些镜像中的大多数已经支持三种基本的对策措施: software stack protection、Data Execution Prevention(DEP/W^X)和 a hardened heap。然而,这些镜像也存在大小和性能限制,使得更高级的对策措施,如ASLR和基于软件的CFI,无法实施。我们希望设计一种方案,可以在最小的大小和性能影响下检查指针的有效性,并抵抗内存泄露漏洞。这排除了使用XOR与随机值以及其他简单的混淆或扰乱指针的方式。我们需要一个具有密码学强度的算法。

在早期的设计决策中选择了使用认证而不是加密。使用认证时,实际的指针值仍然可用,而无需知道秘密密钥。这有许多优点,包括允许处理器的分支预测和调试。此外,通过认证,可以知道发生了损坏的时间,而不仅仅是跳转到一个随机位置并希望崩溃。下一节将描述指针认证的设计。

三、Pointer Authentication

指针认证的基本思想是,在64位架构中,实际的地址空间小于64位。指针值中存在未使用的位,我们可以利用这些位来放置指针认证码(PAC)。在将要写入内存的每个需要保护的指针之前,我们可以插入一个PAC,并在使用之前验证其完整性。想要修改受保护指针的攻击者必须找到/猜测正确的PAC才能控制程序流程。

在程序中,并非每个指针都具有相同的用途。我们希望指针仅在特定的上下文中有效。在指针认证中,这通过两种方式实现:为主要用例使用单独的密钥,并通过对指针和64位上下文计算PAC来实现。指针认证规范定义了五个密钥:两个用于指令指针,两个用于数据指针,以及一个用于在更长的数据序列上计算MAC的单独通用指令。指令编码确定使用哪个密钥。上下文对于隔离与同一密钥一起使用的不同类型的指针非常有用。在计算和验证PAC时,上下文被指定为附加参数,与指针一起使用。

指针认证设计包括三个主要组件:指令(Instructions)、密码学(cryptography)和密钥管理(key management)。接下来将对它们进行描述。

3.1 Instructions

指针认证需要两个主要的操作:计算和添加PAC以及验证PAC并恢复指针值。这分别由PAC和AUT指令集来处理。如果在AUT指令执行期间验证失败,处理器将使用特定模式替换PAC,使得指针值成为非法地址。实际的错误检测是通过非法地址异常来进行的,当解引用无效指针时会触发该异常。这种设计将错误处理与指令解耦,无需使用额外的指令进行错误处理。异常处理程序可以通过检查AUT指令用于表示错误的模式来区分非法地址异常和认证失败。

除了PAC和AUT指令,还有用于去除PAC(XPAC*)和从两个64位输入计算32位认证码的指令(PACGA)。PACGA指令对于保护内存中的敏感数据结构非常有用。例如,可以使用它来计算覆盖所有堆元数据的认证码(AC)值,通过将几个对PACGA指令的调用链接在一起。

ARMv8.3-A架构描述了每个密钥的PAC和AUT指令的变体,并包括组合指令,如验证后返回(RETA*)和验证并跳转(BRA*,BLRA*)。一部分指令被编码在NOP空间中(指令空间的一部分,在早期版本的架构中被视为NOP)。这提供了二进制向后兼容性,允许较旧的ARMv8处理器运行使用这些新指令编译的二进制文件。

3.2 Cryptography

密码学是指针认证的关键部分。我们需要一种快速轻量级的算法,即使在截断为非常短的标签时,也具有足够的密码学强度。所有现有的候选算法,如SipHash和PRINCE,在用于认证指针的构造中具有过高的延迟,可能会对性能造成太大的影响。其中一个问题是PAC必须是由当前环境不可控制的秘密字符串(或密钥)、被标记的指针和本地上下文的函数。这将使得SipHash的输入(以及处理时间)过长,并且像PRINCE这样的分组密码仅允许128位密钥和64位输入。使数据适应PRINCE输入的一种可能的方法是将64位秘密与上下文连接起来以获得用于加密指针的密钥,然后截断密文。然而,这将使攻击者在一定程度上能够控制PRINCE密钥,这对安全性来说非常危险,因为PRINCE的结构及其容易受到相关密钥攻击的影响。

因此,我们设计了QARMA,一种新型的轻量级可调整的分组密码系列。可调整性意味着密码算法对明文的置换取决于秘密密钥和额外的用户可选择的调整参数。

QARMA针对一组非常特定的用例进行了优化。除了在此处使用的截断生成非常短的标签之外,它还设计用于内存加密和构建有密钥哈希函数。它适用于完全展开的硬件实现。该算法属于PRINCE所开创的设计系列,它是一种反射设计,并与密码算法MANTIS相关,但具有不同的设计和比MANTIS更保守的S-盒选择,以减少某些密码分析攻击的可能性。

在用于指针认证时,QARMA的两个输入是指针和上下文。PAC是QARMA截断输出的结果。PAC的大小由处理器虚拟地址大小配置和是否使用“标记地址”功能确定。与PAC不同,“标记地址”功能允许软件为指针添加一个8位的标记,而不影响地址转换。如果未启用“标记地址”功能,则PAC可以使用这些位。由于虚拟地址大小可以配置为32位到52位之间,并且一个位(位55)用于选择虚拟地址空间的高半部分或低半部分,当禁用标记地址时,PAC的大小范围从11位到31位,当启用标记地址时,范围从3位到23位。PACGA指令始终从QARMA的输出生成32位的AC(认证码)。

3.3 Key Management

QARMA使用128位密钥。指针认证规范定义了五个密钥。四个密钥用于PAC和AUT指令(指令/数据和A/B密钥的组合),第五个密钥用于通用的PACGA指令。这些密钥存储在内部寄存器中,EL0(用户模式)无法访问,但与异常级别无关。软件(EL1、EL2和EL3)需要根据需要在异常级别之间切换密钥。通常较高的特权级别控制较低特权级别的密钥。为每个密钥添加了控制位,用于定义异常行为。这允许在需要时按需生成或切换密钥。

这些密钥预计是临时的(对于EL0是每个进程,对于EL1至EL3是每次引导),密钥管理(包括生成高质量的随机数)是软件的责任。

四、Sample Use Cases

本节描述了我们期望使用指针身份验证的不同用例。

4.1 Software Stack Protection

软件堆栈保护是一种针对基于堆栈的缓冲区溢出的对策措施。通常,编译器会对选定的函数进行处理,在进入函数时,在返回地址和堆栈上的缓冲区之间放置一个随机的"canary"值,并在函数返回之前检查"canary"是否被破坏。虽然软件堆栈保护对某些类型的缓冲区溢出是有效的,但它可能会被内存泄露漏洞所攻破。下表说明了代码在进行软件堆栈保护时的工具化。更改部分以红色突出显示:
在这里插入图片描述
基本的指针身份验证指令PAC和AUT可用于实现更强大的堆栈保护版本,开销要小得多:
在这里插入图片描述
上述使用的PACIASP和AUTIASP指令是更通用的PACIA X30, SP和AUTIA X30, SP指令的特殊版本。它们分别使用堆栈指针作为上下文对链接寄存器(X30)进行标记和验证。这些特殊指令位于NOP空间中,这意味着生成的代码与旧处理器保持二进制兼容。如果不需要向后兼容性,可以使用组合的指针认证指令RETAA,它等效于AUTIASP+RET,以节省一条额外的指令。

4.2 Control Flow Integrity (CFI)

CFI(控制流完整性)是程序的一个属性,其中控制流仅遵循预先确定的合法路径。虽然安全的CFI实现需要同时覆盖函数指针和返回地址,但现有的CFI实现通常专注于保护函数指针,而将返回地址的保护留给其他对策,如strong stack protection 或者 shadow/split stack实现。

在CFI中,通过间接调用/跳转可达的函数根据编译时分析或启发式方法进行分类,并限制每个调用点仅调用相同类别的函数指针。通常,这是通过计算和维护内存中的函数指针表,并在每个间接调用/跳转之前添加检查来实现,以确保目标位于表中。

在使用指针认证进行CFI时,一种可能的方法是在加载和动态链接时基于编译时生成的每个指针的类别(上下文)和位置信息,对内存中的函数指针进行预验证。这允许使用在编译时提供的上下文,在调用点使用单个AUT指令对间接函数调用进行验证。

4.3 Binding Pointers to Addresses

指针认证指令可以使用PAC(指针认证代码)指令将指针的值绑定到给定的地址上,其中使用指针的地址作为上下文。这确保了指针的值保持不变,有效地使该位置只读。这对于在程序的生命周期内变化不大的指针非常有用,比如指向只读表格或数据结构的指针。

五、Security Properties

本节描述了指针认证的安全性属性,包括其优点和缺点。请注意,本讨论大部分假设数据执行预防(DEP)已启用,因此代码不可写且数据不可执行。

5.1 Arbitrary memory read

大多数依赖于秘密信息的软件对抗措施都容易受到泄露内存内容的攻击。这包括ASLR(地址空间布局随机化)、软件堆栈保护和其他使用与秘密进行异或运算来混淆指针值的方案。

指针认证旨在抵御内存泄露攻击。PAC是使用具有密码学强度的算法计算的,因此从内存中读取任意数量的经过认证的指针也不会使伪造指针变得更容易。

密钥存储在处理器寄存器中,而这些寄存器对用户模式(EL0)不可访问。因此,内存泄露漏洞不会帮助提取用于PAC生成的密钥。

5.2 Arbitrary memory write

针对内存中可写代码指针的任意内存写入攻击需要猜测或暴力破解PAC,或者找到一种非控制数据的漏洞来修改系统的行为。例如,修改攻击者控制的进程的有效用户ID为root的内核漏洞,以及将内存中的“已认证”标志设置为true以绕过密码检查的远程攻击都是数据攻击的示例。指针认证扩展并没有提供一种通用的机制来防止这些攻击。然而,使用PACGA对敏感数据指针进行认证并保护敏感数据结构可以帮助限制攻击者的能力。

指针认证的一个有趣特性是,即使修改发生在处理器核心之外(例如通过DMA攻击),也可以检测到数据的损坏。这在一般情况下对于代码或其他只读区域可能并没有太大帮助,但在外部访问被限制在物理地址空间的某些区域(例如使用SMMU/IOMMU)时,它可以提供保护。

5.3 Guessing and forging PAC values

猜测目标指针的PAC值的难度取决于PAC的大小,这取决于系统配置。虽然PAC的大小可以低至3位(8分之1的概率),但Linux内核在AArch64架构上默认使用39位虚拟地址空间(512GB)。这在Linux中允许使用24位PAC(400万分之1的概率)。当禁用标记地址时,最大的52位虚拟地址大小配置下,PAC将有11位(2048分之1的概率),这仍然可以与某些ASLR实现相媲美。需要更高安全性的系统(如TrustZone内核和应用程序)可以修改这些执行模式的虚拟地址大小配置,将PAC大小增加到最多31位。

QARMA算法明确设计用于处理短/截断的认证码。我们不期望算法中存在任何可以通过泄露或猜测标签而使后续猜测更容易的快捷方式。实际上,假设成功猜测了一个标签,意味着只知道QARMA输出的少数几位而不是整个密文,而任何在对QARMA进行密码分析攻击时时间或空间复杂性的减少都需要大量已知(甚至是选择的)文本对,这超出了由于有效内存大小而可以收集的信息量。因此,猜测的难度呈指数级增加。任何需要修改或伪造多个指针的攻击都将变得极其昂贵。这实际上对攻击者提高了很高的门槛。

5.4 Pointer substitution attacks

我们预计针对指针认证的大多数攻击形式将是替换一个经过认证的指针为另一个。例如,如果一个指向puts()函数并打印出攻击者提供的字符串的经过认证的函数指针可以被替换为指向system()函数的经过认证的指针,那么这将允许执行攻击者提供的命令。

指针认证设计为不同的用途类别指定了不同的密钥,这些密钥是指令编码的一部分,并在编译时确定。上下文参数可以用于将指针进一步分类为组,以限制可以相互替换的指针。这与细粒度的控制流完整性(Control-Flow-Integrity)没有太大区别,其中每个间接调用点只能根据在编译时生成的控制流图调用函数的一个子集。上下文参数可以用于实施类似的限制。

在架构讨论中,由ARM合作伙伴设计的一种非常有趣的指针替换攻击被ARM描述给我们。该攻击假设除了存在内存破坏漏洞外,还存在一种可以读取堆栈内容并能够在同一堆栈上触发不同功能的原语。Web浏览器可能会满足这些要求。由于在计算返回地址的PAC时使用堆栈指针作为上下文,因此可以收集与不同堆栈地址绑定的多个经过认证的指针。然后,可以使用这些地址来形成一系列的gadget(绑定到堆栈中的原始位置),以执行ROP(Return-Oriented Programming)有效载荷。然而,鉴于攻击者已经拥有的原语的强大功能,很难评估执行此攻击的难度,与以其他方式破坏环境的方式相比。这再次证实了指针认证并非万能解决方案,而且浏览器安全性确实很困难。

5.5 Key management concerns and key reuse attacks

如果攻击者能够猜测密钥或控制与目标进程具有相同密钥的进程,她就可以伪造指针。

第一个关注点是密钥生成时使用的随机性质量。虽然ARM架构不包括熵源,但我们希望假设所有现代基于ARMv8.3-A的设计已经包含一个在早期引导时可以访问的高质量熵源。支持ARMv8的Qualcomm Technologies芯片已经有硬件随机数生成器可用。

第二个问题更常见,特别是在类UNIX系统中,fork()系统调用会创建一个进程的完全副本。这意味着子进程必须具有与其父进程相同的密钥才能继续运行。需要注意的是,这个问题在其他对策中也存在,包括堆栈保护和地址空间布局随机化(ASLR)。

在特权分离设计中,其中一个进程保持特权,而另一个进程降低权限,攻击者如果能够入侵非特权进程,就可以创建在特权进程中有效的经过认证的指针。

在工作进程模型中,根据主进程的需要,会生成多个工作进程来处理请求,远程攻击者可以获得多个、潜在无限次的尝试来暴力破解PAC值,因为所有工作进程都具有相同的密钥,包括由于地址错误而被替换的工作进程。

在这两种情况下,使用fork+exec模型,即子进程在fork之后重新加载自身,可以确保所有进程都使用新的密钥(以及具有ASLR的新地址空间布局)重新启动。由于实施fork+exec需要对设计和现有代码进行更改,并可能影响服务的性能/延迟,内核应该考虑对PAC异常实施特殊处理:当一个进程接收到PAC异常时,内核应该终止不仅是出错的进程,还有所有具有相同密钥的其他进程。这是可行的,因为内核负责管理使用指针认证的进程的密钥。

5.6 Interpreters and Just-in-Time Compilation (JIT)

脚本和字节码解释器为攻击者提供了将数据注入系统并将其解释为指令的良好目标。指针认证不能防止仅针对数据的攻击,但它确实使使用攻击者控制的数据跳转到解释器入口点变得更加困难。

大多数这些运行时环境还支持即时编译(JIT),其中从脚本/字节码动态生成本机代码,以提高性能。一些JIT实现使用可写可执行(RWX)的内存区域,破坏了数据执行保护(DEP),而其他一些JIT实现通过使用别名映射来访问相同物理内存范围的两个虚拟地址(一个可写,一个可执行)来假装遵守DEP/W^X要求。虽然RWX情况可能更糟糕,但这两种方案都为向系统中注入代码提供了目标,潜在地绕过指针认证和其他对策。

随机化可写JIT区域的位置是一种减轻这些攻击的方法。在安全关键环境中,关闭JIT也应该被视为一种选项。

六、Conclusion

在本文中,我们描述了ARMv在本文中,我们描述了ARMv8.3-A规范中引入的ARM指针认证扩展的设计。我们介绍了一些我们预计在工具链中看到的常见用例,并对该方案进行了简要的安全分析。本文中我们提出的场景是一些我们认为指针认证指令会有用的示例。通过提供一种快速验证内存中指针和数据完整性的方式,这些指令将为其他技术和应用程序的出现创造机会。

相关文章:

ARMV8安全特性:Pointer Authentication

文章目录 前言一、Introduction二、Problem Definition三、Pointer Authentication3.1 Instructions3.2 Cryptography3.3 Key Management 四、Sample Use Cases4.1 Software Stack Protection4.2 Control Flow Integrity (CFI)4.3 Binding Pointers to Addresses 五、Security …...

MySQL和Redis更新一致性问题

1. 先更新数据库,再更新缓存 适用场景:适用于对数据一致性要求不是特别高,且缓存更新失败对 系统影响较小的场景。例如,某些非关键数据的缓存更新。 风险:如果缓存更新失败,会导致数据库和缓存数据不一致。…...

(19)夹钳(用于送货)

文章目录 前言 1 常见的抓手参数 2 参数说明 前言 Copter 支持许多不同的抓取器,这对送货应用和落瓶很有用。 按照下面的链接(或侧边栏),根据你的设置了解配置信息。 Electro Permanent Magnet v3 (EPMv3)Electro Permanent M…...

安装lap和cython_bbox失败了很多次!!!终于被我发现了!

先说 lap 试了很多种方式,pip install lap / conda install -c conda-forge lap … 全失败了后面发现 lap 不支持 python > 3.9 的版本使用 pip install lapx 成功! cython_bbox 更难了 一直提示缺少MicroSoft C 14.0 … 大家有需要自行下载&#x…...

异业联盟整合各大行业门店,共享资源

异业联盟系统是一种将不同行业的企业或商家整合在一起,通过资源共享、优势互补、合作推广等方式,实现共同发展和互利共赢的商业合作模式的数字化管理和运营系统。 其具有以下显著优势: 1.拓展客户群体:不同行业的企业联合起来&am…...

前端如何去看蓝湖

首先加入团队,在内容中我们可以看到点击图片,右边出现的图 包含了像素甚至有代码,我们可以参考这个代码。 那么在使用之前我们需要调整好像素,例如我们的像素宽为375,不用去管高,然后这个宽度我们可以去自…...

HTML+CSS+JS 实现3D风吹草动效果(B站视频)

效果&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>3D effect&…...

常用网络概念

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 ☁️运维工程师的职责&#xff1a;监…...

图鸟UI框架在uni-app多端应用开发中的实践与应用

摘要&#xff1a; 随着移动互联网的蓬勃发展&#xff0c;跨平台应用开发已成为行业趋势。本文将探讨图鸟UI框架如何在uni-app开发环境下助力开发者高效构建多端应用&#xff0c;并通过具体案例展示其在实际项目中的应用效果。 一、引言 在移动应用开发领域&#xff0c;跨平台…...

特征值究竟体现了矩阵的什么特征?

特征值究竟体现了矩阵的什么特征&#xff1f; 简单来说就是x经过矩阵A映射后和自己平行 希尔伯特第一次提出eigenvalue,这里的eigen就是自己的。所以eigenvalue也称作本征值 特征值和特征向量刻画了矩阵变换空间的特征 对平面上的任意向量可以如法炮制&#xff0c;把他在特征…...

C语言-顺序表

&#x1f3af;引言 欢迎来到HanLop博客的C语言数据结构初阶系列。在这个系列中&#xff0c;我们将深入探讨各种基本的数据结构和算法&#xff0c;帮助您打下坚实的编程基础。本次我将为你讲解。顺序表&#xff08;也称为数组&#xff09;是一种线性表&#xff0c;因其简单易用…...

OpenCV漫水填充函数floodFill函数的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 功能描述 ffloodFill函数是OpenCV库中用于图像处理的一个功能&#xff0c;它用于填充与种子点颜色相近的连通区域。这个函数在很多场景下都非常有用&#x…...

redis内存分析

阿里云redis集群对key进行hash后保存在对应的后端节点&#xff0c;使每个节点的key数量大致相同&#xff0c;但是如果存在大key&#xff0c;就会导致单个节点内存用满&#xff0c;可以使用redis-rdb-tools 或rdr来对内存进行分析。 redis-rdb-tools redis-rdb-tools通过对dum…...

redis批量删除keys,用lua脚本。

文章目录 现象解决方法 现象 系统报错&#xff1a; misconf redis is configured to save ....后查看机器内存。 是内存满了&#xff0c;需要删除其中的key 解决方法 (1) 编写一个脚本&#xff0c;放在redis-cli.exe同一个目录 (2) 脚本内容如下&#xff1a; -- 使用Lua脚…...

Python-找客户软件

软件功能 请求代码&#xff1a; 填充表格&#xff1a; 可以search全国各个区县的所有企业信息&#xff0c;过滤手机号、查看是否续存/在业状态。方便找客户。 支持定-制-其他引-留-阮*件&#xff08;XHSS&#xff0c;DYY&#xff0c;KS&#xff0c;Bi-li*Bi-li&#xff09; V*…...

STM32 - PWR 笔记

PWR&#xff08;Power Control&#xff09;电源控制 PWR 负责管理 STM32 内部的电源供电部分&#xff0c;可以实现 可编程电压监测器 和 低功耗模式 的功能 可编程电压监测器&#xff08;PVD&#xff09;可以监控VDD电源电压&#xff0c;当VDD下降到PVD阀值以下或上升到PVD…...

标准盒模型和怪异盒子模型的区别

在 CSS 中&#xff0c;标准盒模型和怪异盒模型是两种不同的盒子模型计算方式&#xff0c;主要区别如下&#xff1a; 一、标准盒模型&#xff08;content-box&#xff09; 1. 定义与组成 - 标准盒模型是 CSS 中默认的盒模型。 - 它由内容区域&#xff08;content&#xff09;、…...

推荐算法——MRR

定义&#xff1a; MRR计算的是第一个正确答案的排名的倒数&#xff0c;并对所有查询取平均值。它衡量了模型在排序结果中快速找到正确答案的能力。 其中&#xff1a; Q 是查询的总数。ranki​ 是第 i 个查询中第一个正确答案的排名&#xff08;位置&#xff09;。如果第一个正…...

idea中打开静态网页端口是63342而不是8080

问题&#xff1a; 安装了tomcat 并且也配置了环境&#xff0c;但是在tomcat下运行&#xff0c;总是在63342下面显示。这也就意味着&#xff0c;并没有运行到tomcat环境下。 找了好几个教程&#xff08;中间还去学习了maven&#xff0c;因为跟的教程里面&#xff0c;没有maven,但…...

Vue3框架搭建3:配置说明-prettier配置

1、配置说明&#xff1a; .prettierrc.json{"$schema": "https://json.schemastore.org/prettierrc","semi": false,"tabWidth": 2,"singleQuote": true,"printWidth": 100,"trailingComma": "no…...

SQL MySQL定时器/事件调度器(Event Scheduler)

事件调度器&#xff08;Event Scheduler&#xff09;在MySQL数据库系统中是一个强大的功能组件&#xff0c;它允许用户定义一系列称为“事件”的数据库对象&#xff0c;这些事件在指定的时间或时间间隔自动执行预定义的SQL语句或操作。事件调度器通过维护一个时间计划表来管理这…...

从0到1构建渠道运营体系:实战案例与策略指南

引言 在当今竞争激烈的市场环境中&#xff0c;有效的渠道运营是企业实现产品或服务快速触达目标用户、提升市场份额的关键。从零开始构建一个高效的渠道运营体系&#xff0c;不仅需要深思熟虑的策略规划&#xff0c;还需要灵活应变的实战操作。本文将结合实战案例&#xff0c;…...

Java版Flink使用指南——将消息写入到RabbitMQ的队列中

大纲 新建工程新增依赖 编码自动产生数据写入RabbitMQ 测试工程代码 在 《Java版Flink使用指南——从RabbitMQ中队列中接入消息流》一文中&#xff0c;我们介绍了如何使用Java在Flink中读取RabbitMQ中的数据&#xff0c;并将其写入日志中。本文将通过代码产生一些数据&#xf…...

python excel openpyxl

python excel LTS 在开始之前&#xff0c;确保已经安装了 Python 和所需的库。 主要使用以下库&#xff1a; openpyxl&#xff1a;用于读取和写入 Excel 文件。 pandas&#xff1a;用于数据处理和分析。 xlwings&#xff1a;用于将 Python 与 Excel 连接&#xff0c;实现双向…...

C++八股(一)

目录 一、new和malloc ⭐ 二、class和struct的区别 ⭐ 三、char和int之间的转换 四、什么是野指针和悬挂指针 ⭐ 五、NULL和nullptr区别⭐ 六、指针常量和常量指针有何区别⭐ 七、物理内存和虚拟内存的区别⭐ 八、重载、重写和隐藏的区别⭐ 九、简述面向对象(OOP)的…...

【Git的基本操作】版本回退 | 撤销修改的三种情况 | 删除文件

目录 5.版本回退 5.1选项hard&后悔药 5.2后悔药&commit id 5.3版本回退的原理 6.撤销修改 6.1情况一 6.2情况二 6.3情况三 ​7.删除文件 Git重要能力之一马&#xff0c;版本回退功能。Git是版本控制系统&#xff0c;能够管理文件历史版本。本篇以ReadMe文件为…...

STM32-I2C

本内容基于江协科技STM32视频学习之后整理而得。 文章目录 1. I2C通信1.1 I2C通信简介1.2 硬件电路1.3 I2C时序基本单元1.3.1 起始条件和终止条件1.3.2 发送一个字节1.3.3 接收一个字节1.3.4 发送应答和接收应答 1.4 I2C时序1.4.1 指定地址写1.4.2 当前地址读1.4.3 指定地址读…...

04.ffmpeg打印音视频媒体信息

目录 1、相关头文件 2、相关结构体 3、相关函数 4、函数详解 5、源码附上 1、相关头文件 #include <libavformat/avformat.h> 包含格式相关的函数和数据结构 #include <libavutil/avutil.h> 包含一些通用实用函数 2、相关结构体 AV…...

微信开发授权登录梳理总结

授权登录流程对比 微信公众号/网页 微信文档地址&#xff1a;https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html 流程图如下&#xff1a; 特殊说明&#xff1a; 步骤1拼接的微信地址是&#xff1a;https://open.weixin.qq…...

HTML5实现我的音乐网站源码

文章目录 作者&#xff1a;[xcLeigh](https://blog.csdn.net/weixin_43151418) 1.设计来源1.1 界面效果1.2 轮播图界面1.3 音乐播放界面1.4 视频播放界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作…...