在 .NET 中使用 FixedTimeEquals 应对计时攻击

  计时攻击  

在计算机安全中,计时攻击(Timing attack)是旁道攻击 (Side-channel attack) 的一种,而旁道攻击是根据计算机处理过程发出的信息进行分析,包括耗时,声音,功耗等等,这和一般的暴力破解或者利用加密算法本身的弱点进行攻击是不一样的。

  举个例子  

假如您有一个后端 webapi, GetConfig 接口用来获取配置信息,调用时需要在 Header 中传入一个秘钥,然后判断是否正确并进行返回,如下

X-Api-Key: x123
[HttpGet]
public IActionResult GetConfig()
{var key = Request.Headers["X-Api-Key"].FirstOrDefault();if (key != "x123"){return Unauthorized();}return Ok(configuration);
}

注意,这里我们为了判断两个字符串相等,通常会使用 == 或者 != , 实际上背后使用了 String 的 Equals() 方法,如下

// Determines whether two Strings match.
public static bool Equals(string? a, string? b)
{if (object.ReferenceEquals(a, b)){return true;}if (a is null || b is null || a.Length != b.Length){return false;}return EqualsHelper(a, b);
}

而内部又使用了 SequenceEqual() 方法

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool EqualsHelper(string strA, string strB)
{Debug.Assert(strA != null);Debug.Assert(strB != null);Debug.Assert(strA.Length == strB.Length);return SpanHelpers.SequenceEqual(ref Unsafe.As<char, byte>(ref strA.GetRawStringData()),ref Unsafe.As<char, byte>(ref strB.GetRawStringData()),((uint)strA.Length) * sizeof(char));
}

大概的逻辑是,先判断两个字符串长度是否一致,如果不是,直接返回 false,然后循环字符串进行逐位对比,一旦发现不相同,直接返回 false,伪代码如下

public bool Equals(string str1, string str2)
{if (str1.Length != str2.Length) {return false;} for (var i = 0; i < str1.Length; i++){if (str1[i] != str2[i]){return false;}} return true;
}

这里有一个问题是,如果字符串第一位不相同,直接就返回 false,如果最后一位不相同,那就需要遍历到最后,然后返回 false。不一样的字符串,计算的时长可能不一致。

  尝试破解  

假如用户知道了我们的秘钥的固定长度是 4 位。

GET /GetConfig  
X-Api-Key:a000
Cost: 2ns

本次耗时了 2ns, 接下来又输入 b000, c000....

GET /GetConfig  
X-Api-Key:b000
Cost: 2nsGET /GetConfig  
X-Api-Key:c000
Cost: 2ns ...GET /GetConfig  
X-Api-Key:x000
Cost: 4ns

直到输入了 x000, 发现其他的耗时都是 2ns, 而这里是 4ns,大概率判定第一位是 x。

注意,这里的测试进行了放大,可能每个 case 分别调用了 100 次,然后统计了 P50(中位数)得出的结果。

然后用同样的方法,测试第二位,第三位....., 最终破解拿到了秘钥。

  使用固定时间的算法  

虽然看上去有点扯,但确实是真实存在的,包括大名鼎鼎的针对 TLS 的 Lucky 13 攻击,有兴趣的同学可以看一下。在安全性要求比较高的场景中,确实要考虑到计时攻击,当涉及到安全时,还是宁可信其有。

所以我们的算法的执行耗时应该是固定的,不应该在不匹配时,就立即返回,我们尝试改造一下代码

public bool Equals(string str1, string str2)
{if (str1.Length != str2.Length){return false;}bool reult = true;for (var i = 0; i < str1.Length; i++){if (str1[i] != str2[i]){reult = false;}}return reult;
}

不管怎么样,都会遍历完整个字符串,然后返回结果,看上去没什么问题,时间总是固定的,但在现代的 CPU 和 .NET 上却不是的,因为我们要考虑到分支预测,特别是 if 条件。

好吧,那我们调整一下代码

public bool Equals(string str1, string str2)
{if (str1.Length != str2.Length){return false;}bool reult = true;for (var i = 0; i < str1.Length; i++){ reult &= str1[i] == str2[i]; }return reult;
}

我们用了运算符 &,来代替 If, 只有全部为 true 时,才会返回 true,其中任意一个字符不匹配,就会返回 false,看上去不错。

但是,还有一些问题,对于bool类型的 result (true/false), 我们的 .NET JIT 和 x86 指令执行仍然会进行一些优化,我们再调整一下代码

public bool Equals(string str1, string str2)
{if (str1.Length != str2.Length){return false;}int reult = 0;for (var i = 0; i < str1.Length; i++){ reult |= str1[i] ^ str2[i]; }return reult == 0;
}

我们把 bool 改成了 int 类型,然后使用了运算符 ^ 和 |,同样的,只有字符串全部匹配时,result 为 0,,才会返回 true, 其中任意一个不匹配,result 就不为 0,会返回 false。

最后,为了防止 JIT 对我们的代码进行其他的优化,我们可以加一个特性,告诉 JIT 不要管它,就像这样

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public bool Equals(string str1, string str2)
{if (str1.Length != str2.Length){return false;}int reult = 0;for (var i = 0; i < str1.Length; i++){ reult |= str1[i] ^ str2[i]; }return reult == 0;
}

上面我们实现了一个针对字符串比较的固定时间的算法,来应对计时攻击。

实际上, 从 .NET Core 2.1 开始就已经做了内置支持,我们可以直接使用 FixedTimeEquals 方法, 看一下它的实现

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static bool FixedTimeEquals(ReadOnlySpan<byte> left, ReadOnlySpan<byte> right)
{ if (left.Length != right.Length){return false;}int length = left.Length;int accum = 0;for (int i = 0; i < length; i++){accum |= left[i] - right[i];}return accum == 0;
}

现在用起来也很方便:

var result = CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes(str1), Encoding.UTF8.GetBytes(str2)
);

  总结  

在安全性比较高的场景中,应该要考虑到计时攻击,可以使用固定时间的算法来应对。在其他的开发语言中,也都有本文中类似的算法,而在 .NET 中,现在我们可以直接使用 CryptographicOperations.FixedTimeEquals。

f5986f626179afa1202db4d69a1f1c41.png

07b62a816e79366b41361ae249e5fd7d.gif

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

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

相关文章

解读大型网站系统架构的演化

解读大型网站系统架构的演化 大型网站的架构是根据业务需求不断完善的&#xff0c;根据不同的业务特征会做特定的设计和考虑&#xff0c;本文只是讲述一个常规大型网站会涉及的一些技术和手段。作者&#xff1a;李平来源&#xff1a;LEE的博客前言 一个成熟的大型网站&#xff…

【ArcGIS风暴】西北地区气象台站年均NDVI与年均气温和降水的相关性分析

在研究植被动态变化与气候的关系时,通常通过计算植被NDVI值与气温和降水的相关系数来描述相关性的大小。如下图所示,计算了西北地区分布的气象台站与气温和降水的相关性并作图可视化。 下面详细说明整个实现过程。 一、计算相关系数 1. 原理分析 通过计算年均N…

python 全解坦克大战 辅助类 附完整代码【雏形】

我正在博客之星评选&#xff0c;欢迎投票给我 会从投票人中抽奖机械键盘书&#xff0c;中了会私聊地址 投票连接是&#xff1a;https://bbs.csdn.net/topics/603955346 投票连接是&#xff1a;https://bbs.csdn.net/topics/603955346 投票连接是&#xff1a;https://bbs.csdn.…

vc++ mfc中拖动效果的实现 借助于CImageList

拖动是界面编程频繁使用的一个效果&#xff0c;在windows系统下可谓大行其道。纵观时下的应用软件几乎各个都支持各种各样拖动的效果&#xff0c;windows7更是把拖动做到了极致。其实说起来拖动的实现也很简单&#xff0c;对于有句柄的对象都可以通过MoveWindow或SetWindowPos实…

从浏览器地址栏输入url到显示页面的步骤

从浏览器地址栏输入url到显示页面的步骤(以HTTP为例)- 在浏览器地址栏输入URL- 浏览器查看缓存&#xff0c;如果请求资源在缓存中并且新鲜&#xff0c;跳转到转码步骤 - 如果资源未缓存&#xff0c;发起新请求 - 如果已缓存&#xff0c;检验是否足够新鲜&#xff0c;足够…

有序的Map集合--LinkedHashMap

提出问题&#xff1a; 在写一个dao的时候&#xff0c;我的需求是这个dao是一个万能的&#xff0c;目前的方法只有一个查询出实体类对应的表中所有的数据&#xff0c;通过传入的对象&#xff0c;利用反射获取实体类中的属性名&#xff0c;属性类型&#xff0c;利用字符串拼接获取…

Leetcode之仅仅反转字母

1 题目 给定一个字符串 S,返回 “反转后的” 字符串,其中不是字母的字符都保留在原地,而所有字母的位置发生反转。 示例 1:输入:"ab-cd" 输出:"dc-ba" 示例 2:输入:"a-bC-dEf-ghIj" 输出:"j-Ih-gfE-dCba" 示例 3:输入:&qu…

【SignalR全套系列】之在.Net Core 中实现长轮询

微信公众号&#xff1a;趣编程ACE关注可了解更多的.NET日常实战开发技巧&#xff0c;如需源码 请后台留言 源码;前文回顾【SignalR全套系列】之在.Net Core 中实现Server-Send Events消息推送【SignalR全套系列】之在.NetCore中实现WebSocket双工通信【SignalR全套系列】之在.N…

完美解决ArcGIS10.2和Erdas9.2软件冲突的方法:共存!

用过ArcGIS和Erdas软件的都知道&#xff0c;二者存在着服务的冲突&#xff0c;为了解决共存的问题&#xff0c;笔者曾多次重装系统&#xff0c;但未能如愿以偿。其实不需要相互关闭服务如此麻烦。那如何在安装有arcgis的电脑安装erdas并解决冲突呢&#xff1f;直接上视频教程。…

架构师之路16年精选50篇

2016精选索引&#xff0c;点击标题阅读相关文章。【方法论】《秒杀系统架构优化思路》《分布式ID生成器》《互联网架构&#xff0c;如何进行容量设计》《线程数究竟设多少合理》《单点系统架构的可用性与性能优化》《关于负载均衡的一切》《异构服务器负载均衡及过载保护》《LV…

yii 前后台分离及登陆验证

2019独角兽企业重金招聘Python工程师标准>>> 比较合理的做法其实是分成两个框架来布署&#xff1b;然而这样说法也太绝对。 事实上是针对不同系统&#xff0c;应采用不同的方法。如为CMS系统&#xff0c;则不需很复杂的权限管理&#xff0c;但如果有管理员与会员之分…

双谷人才财务管理(序)

IT是一个迅速发展的行业&#xff0c;教育是一个良心的行业&#xff0c;两者交集——IT培训&#xff0c;在整个市场中占有一个不可或缺的地位。好多大学生&#xff0c;抱怨找不到工作&#xff1b;好多企业找不到合适的程序员&#xff0c;这几年这个问题越来越严重。。。。于是IT…

Android之打开手机系统相册

1、需求 打开系统相册&#xff0c;获取图片进行扫描操作 2、代码实现 Intent pickIntent new Intent(Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI);pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");Ca…

Kibana

2019独角兽企业重金招聘Python工程师标准>>> Kibana是一个基于浏览器页面的Elasticsearch前端展示工具。Kibana全部使用HTML语言和Javascript编写的&#xff0c;查询语法是基于Lucene的查询语法。允许布尔运算符、通配符和字段筛选。注意关键字要大写 全文搜索 在搜…

电脑QQ能登上,网页打不开的解决办法

打开360卫士&#xff0c;在功能大全里选择网络优化&#xff0c;断网急救箱。 可以看到DNS服务异常、浏览器配置异常&#xff0c;点击立即修复。

个人黑名单 抄袭耻辱墙

抄袭耻辱墙 博主抄袭文原文我爱Python数据挖掘https://blog.csdn.net/weixin_38037405/article/details/125862095https://blog.csdn.net/A757291228/article/details/117464313黄埔数据分析https://blog.csdn.net/weixin_39060517/article/details/118024847https://blog.csdn…

快速掌握 ASP.NET 身份认证框架 Identity(一)

推荐关注「码侠江湖」加星标&#xff0c;时刻不忘江湖事ASP.NET Core 内置了一个强大的身份认证框架 Identity&#xff0c;掌握它可以让我们快速开发高安全的身份认证功能&#xff0c;不仅如此&#xff0c;它还是一个基于数据库的用户管理系统&#xff0c;其中包含了大量的辅助…

浅谈大型web系统架构

动态应用&#xff0c;是相对于网站静态内容而言&#xff0c;是指以c/c、php、Java、perl、.net等服务器端语言开发的网络应用软件&#xff0c;比如论坛、网络相册、交友、BLOG等常见应用。动态应用系统通常与数据库系统、缓存系统、分布式存储系统等密不可分。   大型动态应用…

Android之webview长按超链接类型获取链接文字及url、长按图片链接类型分别获取图片和链接的url

1 、需求 webview长按超链接获取链接文字及urlwebview长按图片链接类型获分别获取图片和链接的url 2、解决办法 1)、设置webview的OnLongClickListener事件,关键代码如下 companion object {const val LINK_TYPE = 1const val IMAGE_LINK_TYPE = 2}var mHandler = object :…

PostgreSQL 统计信息pg_statistic格式及导入导出dump_stat - 兼容Oracle

标签 PostgreSQL , dump_stat , 统计信息 , 导出导入 背景 《PostgreSQL 规格评估 - 微观、宏观、精准 多视角估算数据库性能(选型、做预算不求人)》 EXPLAIN是PG数据库用于输出SQL执行计划的语法&#xff0c; 1、生成的执行计划中包含COST一项。 如果校准了成本因子&#xff0…