<button id="ei02c"><ol id="ei02c"></ol></button>
            1. <div id="ei02c"></div>

                    1. 安基网 首页 安全 安全学院 查看内容

                      使用浏览器的计算力对抗密码破解

                      2019-3-28 01:07| 投稿: xiaotiger |来自: 互联网


                      免责声明本站系公益性非盈利IT技术普及网本文由投稿者转载自互联网的公开文章文末均已注明出处其内容和?#35745;?#29256;权归原网站或作者所有文中所述不代表本站观点若有无意侵权或转载不当之处请从网站右下角联系我们处理谢谢合作

                      摘要: 本文前半部分?#30772;?PBKDF 函数的意义后半部分探讨在前端计算的可行性前言几乎每隔一段时间就会听到XX 网站被拖库的新闻之后又会出现一些报道分析该网站使用最多的密码是什么有多少等等众所周知密码在数据库中通常是以 Hash ...

                      来源:https://www.cnblogs.com/index-html/p/6045984.html

                      本文前半部分?#30772;?PBKDF 函数的意义后半部分探讨在前端计算的可行性

                      前言

                      几乎每隔一段时间就会听到XX 网站被拖库的新闻之后又会出现一些报道分析该网站使用最多的密码是什么有多少等等

                      众所周知密码在数据库中通常是以 Hash 值存储的并?#19968;?#21152;?#25628;Ρ?#25915;击者即使知道具体的 Hash 算法也只能暴力破解照理说这是极其费劲的然而现实中却总有大量密码被破解是什么导致安全性如此脆弱

                      ?#31185;?#21407;因莫过于这两点口令密码算法成本

                      口令密码

                      密码可以记在很多地方最常见的就是记在自己脑袋里当然还可以记在属于你的物品上例如小本子卡片等等反正不用脑子记不如设置的很长很乱例如

                      QQ: n5Py 2r8W qGyg 4tU6
                      GMail: 3TkS mVwQ hUrs wtmA
                      ...
                      

                      这种无意义的长串作密码是很安全的即使它们的 Hash 值以及算法泄露攻击者想得到明文只能暴力穷举所有组合

                      泄露的值是 BF656DEC5DD8BA0B泄露的算法是 f(x)开?#35760;?#20030;...
                      尝试组合 f(x) 结果
                      aaaa aaaa aaaa aaaa 02F49B3EA5592B14 
                      aaaa aaaa aaaa aaab BD4E960D990DA3F3 
                      ... 
                      n5Py 2r8W qGyg 4tU5 4CEA28A904326A26 
                      n5Py 2r8W qGyg 4tU6 BF656DEC5DD8BA0B 
                      

                      就算只有字母和数字也要近 10^28 次才猜到这是个天文数字几乎不可行所以这种类型的密码还是很安全的

                      然而现实中这么做的并不多物品需要随身携带非常不便要是弄丢或者被偷就更麻烦了除?#21069;?#23427;们都背下来但这不又回到记在脑袋里这种方式了

                      脑袋确实很安全但容量也很有限像上面?#20405;?#27627;无规律的字串背一句都难更别说多个了所以大家多少都会选些有意义有规律的字串作为密码例如 iloveyou2016qwert12345或是手机号生日等组合这种不用死记硬背的字串就是口令pass word

                      口令虽然方便但缺陷也很明显因为它是有规律的所以猜起来就容易多了攻击者只需测试常用单?#39318;?#21512;没准就能猜到了

                      泄露的值是 2B649D47C4546A3E泄露的算法是 f(x)开始跑?#20540;?..
                      尝试组合 f(x) 结果
                      ...
                      qwert yuiop 52708233CFFD6BFD 
                      qwert asdfg CD07933880702B97 
                      qwert zxcvb 343F78782D73AB3A 
                      qwert 12345 2B649D47C4546A3E 
                      

                      这个过程就是所谓的跑?#20540;䡱?#19968;本好的?#20540;?#21487;以极大的提升猜中几率

                      算法成本

                      在?#20540;?#30456;同的情况下速度就显得尤为重要了每秒可以猜多少次这?#27599;?#20855;体的算法

                      例如 MD5 函数每次调用大约需要 1 微秒这意味着每秒可以猜 100 万次而且这还只是单线程的速度用上多并发更是恐怖

                      由此可见算法越快对破解者就越有利假如每次调用需要 10 毫秒那么每秒只能猜 100 次这样就足足慢了一万倍

                      然而不幸的是常用的 Hash 函数都是很快的因为它们生来就有多种用途并非为口令处理而设计例如计算一个大文件的校验值速度显然很重要

                      所以用 MD5SHA256 之类的快函数处理口令是不合理的包括一些简单的变种例如 MD5(SHA256(x))仍然属于快函数一旦 Hash 值和算法泄露很容易被跑?#20540;?#30772;解

                      现实中由于不少网站使用了快函数?#21019;?#29702;口令因此数据库泄露后大量口令被还原也就在所难免了

                      增加成本

                      虽然 Hash 函数单次执行很快但我们可以反复执行大?#30475;?#25968;这样总体耗?#26412;?#21464;长了例如

                      function slow_sha256(x)
                       for i = 0 to 100000
                       x = sha256(x)
                       end
                       return x
                      end
                      

                      在密码学中这种方式叫做 拉伸现实中有不少方案例如 PBKDF2 它没有重头设计一种新算法而是对现有的函数进行封装从而更适合用于口令处理

                      function pbkdf2(fn, ..., iter)
                       ...
                       for i = 0 to iter
                       ...
                       x = fn(x, ...)
                       ...
                       end
                       ...
                       return x
                      end
                      

                      它有一个迭代参数用于指定反复 Hash 的次数 迭代次数越多执行时间越长破解也就越困难

                      PBKDFPassword-Based Key Derivation Function基于口令的密钥导出函数顾名思义就是输入口令?#20445;?#26377;规律的字串输出密钥?#20445;?#26080;规律的长串的函数并且计算过程会消耗一定资源本质上也是 Hash 函数输出结果称之 DKderived key

                      前端拉伸

                      拉伸次数越多虽然越安全但这是以消耗服务端大量计算资源为代价的为了能在安全和性能之间折衷通常只选择几十到几百毫秒的计算时间

                      服务端的计算量如此沉重以至于不堪重负而如今的?#31361;?#31471;系统资源却普遍过剩能否让用户来分担一些计算量

                      听起来似乎不可行毕竟前端意味着公开将密码相关的算法公开不会产生安全问题吗


                      先来回顾下传统网站是如何处理口令的 前端通常什么都不做仅仅用于提交口令都是由后端处理的

                      现在我们尝试对前端进行?#33041;? 当用户在注册登录等页面中提交时不再发送原始口令而是口令的 DK

                      后端则不做任何改动当然这会影响已有账号的使用这里暂时先不考虑假设这是个新网站

                      这样即使用户的口令很简单但相应的 DK 却仍是个毫无意义的长串通过 DK 的 Hash 值是极难还原出 DK 的在本文开头就提到过了)

                      当然攻击者更?#34892;?#36259;的不是 DK而是口令这倒是可以破解的 只需将前后端算法结合形成一个新函数

                      F(x) = server_hash(client_hash(x))
                      

                      用这个最终函数 F 跑?#20540;?#36824;是可以猜口令的

                      尝试组合 耗时 F(x) 结果
                      ...
                      qwert yuiop 1s 1C525DC73898A8EF 
                      qwert asdfg 1s F9C0A131F43F1969 
                      qwert zxcvb 1s 08F026D689D26746 
                      ...
                      

                      只不过其中有 client_hash 这道障碍破解速度就大幅降低了

                      所以我们需要

                      • 一个缓慢的 client_hash增加跑?#20540;?#30340;成本
                      • 一个快速的 server_hash防止 DK 泄露

                      这样就能将绝大多数的计算转移到前端后端只需极少的处理即可实现一个高强度的密码保护系统

                      对抗预算

                      由于前端的一切都是公开的所以 client_hash 的算法大家都知道攻击者可以把常用口令的 DK 提前算出来编成一个新?#20540;?#23558;来拖库后直接跑这个新?#20540;保?#23601;能节省大量时间了

                      对于这种方式就需要使用加盐处理事实上 PBKDF 本身就需要提供盐参数例如选择用户 ID 作为盐

                      function client_hash(password, salt) {
                       return pbkdf2(sha256, password, salt, 1000000);
                      }
                      client_hash(888888, [email protected]); // b80c97beaa7ca316...
                      client_hash(888888, [email protected]); // 465e26b9d899b05f...
                      

                      这样即使口令相同但用户不同生成的 DK 也是不同的攻击者只能针对特定账号生成?#20540;?#36866;用?#27573;?#23601;小多了

                      更进一步我们甚至可将网站 ID?#24065;?#25530;入盐中

                      function client_hash(password, salt) {
                       return pbkdf2(sha256, password, salt, 1000000);
                      }
                      client_hash(888888, [email protected]/www.site-a.com); // 77a1b139aa93ac8b...
                      client_hash(888888, [email protected]/www.site-b.com); // fab6b82e6a1d17d7...
                      

                      这样即使同样的账号密码?#20445;?#22312;不同网站上生成的 DK 也是不一样了

                      思考题ID 是公开的能不能选个隐蔽的字段作为 client_hash 的盐

                      DK 泄露

                      DK 诞生于前端后端对其 Hash 之后就不?#21019;?#22312;了所以它是个临时值理想情况下它是不会泄露的

                      但在某些场合DK 还是有可能泄露的例如服务器中毒网络传输被窃听等都能导致 DK 泄露

                      DK 泄露后攻击者就能控制该账号了这是无法避免的但?#20197;?#30340;是DK 只是个无意义的长串而已攻击者并不知道其背后的那个有意义的口令是什么因此其他使用类似口令的账号就幸免于难了

                      攻击者若要通过 DK 还原口令就得用 client_hash 算法跑?#20540;? 这个成本依然很大相比之前的最终函数 F?#20445;?#21482;是少算一次 server_hash 而已server_hash 本来就很快可以忽略不计所以即使 DK 泄露破解口令?#35759;?#22522;本没降低

                      账号被盗口令拿不到?#20445;?#36825;就是前端 Hash的意义

                      额外意义

                      前端的拉伸计算使得用户登陆时会耗费一定的系统资源这个副作用事实上也能起到一定的防御效果

                      对于普通用户来说登陆时额外花费几秒时间或许影响不大但对于频繁登录的人来说将是一个极大的开销有谁会极其频繁的登录这很可能就是?#30333;部?#25915;击者 他们从其他地?#33050;?#21040;一堆账号口令然后来这里撞?#20284;?#30475;看能成功登上多少

                      由于我们是用 DK 登录的因此攻击者也必须将待测的口令先算出 DK 再提交于是会增加不少计算成本这和上一篇的 Proof-of-Work 有点类似

                      如同拉伸弹簧需要付出能量拉伸 Hash 同样需要投入实实在在的算力

                      优化体验

                      事实?#29616;?#35201;设计的合理完全可以将拉伸计算的等待降到最小例如当用户输完账号和密码后程序立即开始计算 DK而不是等到提交时才开始计算如果网站有验证码的话即可在用户输入的同时进行计算这样就能大幅提升用户体验

                      小结

                      本篇提到的 3 类密码

                      类型安全性易用性说明无意义的密钥高差很难记住只能储存在外部增加了保管成本有规律的口令低好容易记住但也容易被跑?#20540;?#25915;击口令转成密钥中好同上但转?#36824;?#31243;很耗时提高跑?#20540;?#30340;成本

                      两种 Hash 函数

                      • 快函数MD5SHA256 等输入数据很长很没规律时使用
                      • 慢函数PBKDF2bcrypt 等输入数据容易猜到时使用

                      关于前端 Hash?#20445;?#20854;实算是 零知识证明?#20445;zero-knowledge proof的一种什么是零知识证明这里套用一个经典的例子

                      你拥有一个宝库可以通过念咒语来开门有天你想在朋友面前证明你能打开宝库但又不想让他听到咒语这该如何解决

                      正好他知道你的宝库里有个独一无二的宝物如果能取出来给他看自然就能证明你能打开这样就无需带他到场自己单?#26469;?#24320;取出宝物然后拿给他看就行了于是就可以在不暴露咒语的同时证明你能打开

                      这就是零知识证明 证明者在不透露任何有用信息的情况下使验证者相信某个论断是正确的

                      ?#23548;?#24212;用

                      前端 Hash的做法在密码管理插件中很常见用户的口令不再发往后端而是仅仅用于生成 DK然后再根据 DK给不同账号生成不同的密码这样就算遇到最坏的情况例如服务器中毒传输窃听后端明文存储等导致密码泄露也不会暴露你的口令最多损失某个账号而不影响其他账号

                      另外口令也不再填写于原先的文本框中而是填在插件的界面上插件算出 DK 后自动填到原先的文本框这样可以降低口令泄露的风险例如网页中可能潜伏着恶意脚本

                      Web 应用

                      不过现实中天生内置了前端 KDF 计算的网站并不多不像插件可以调用本地程序性能高且稳定浏览器则是良莠不齐不同的版本性能差异很大因此计算时间很不稳定

                      另外在曾经很长一段时间里IE 时代浏览器的计算力都十分?#25302;n?#20197;至于大家都保留了前端计算意义不大一切都由后端计算的观念不过如今主流浏览器的性能?#35757;?#21040;大幅提升甚至 HTML5 还引入了 WebCrypto 规范JS 可直接调用浏览器内置的密码学算法库其中就包括了 PBKDF2由于是原生实现的因此性能非常的高这里有个简单的演示

                      https://etherdream.github.io/FunnyScript/pbkdf2/test.html

                      更好的 KDF

                      当然作为口令 Hash 函数PBKDF2 还不是最好的因为它只是简单地套用了现有的 Hash 函数而已而非针对性的进行设计

                      2015 年 Password Hashing Competition 的胜出者 argon2就非常先进了它不仅可设置时间成本迭代次数还能设?#27599;?#38388;成本内存占用使得算法重度?#35272;的?#23384;这样对于一些计算力很强但存储性能一般的设备例如 GPUASIC 等破解优势就大幅降低了同时它还支持多线程计算因此同样的时间里可投入更多的工作量用于 Hash 计算这让破解成本也增加数倍



                      小编推荐欲学习电脑技术系统维护网络管理编程开发和安全攻防等高端IT技术请 点击这里 注册账号公开课频道价值万元IT培?#21040;?#31243;免费学让您少走弯路事半功倍好工作升职?#26377;?/font>

                      本文出自https://www.toutiao.com/a6672930999829004808/

                      免责声明本站系公益性非盈利IT技术普及网本文由投稿者转载自互联网的公开文章文末均已注明出处其内容和?#35745;?#29256;权归原网站或作者所有文中所述不代表本站观点若有无意侵权或转载不当之处请从网站右下角联系我们处理谢谢合作


                      鲜花

                      ?#24080;?/a>

                      雷人

                      路过

                      鸡蛋

                      相关阅读

                      最新评论

                       最新
                      返回顶部
                      ½11ѡ5㹫ʽ