随机数在计算机应用中使用的比较普遍,最为熟知的即是在密码学中的应用。本文主要是讲解随机数使用致使的一些Web安全风。php
咱们先简单了解一下随机数java
随机数分为真随机数和伪随机数,咱们程序使用的基本都是伪随机数,其中伪随机又分为强伪随机数和弱伪随机数。程序员
真随机数,经过物理实验得出,好比掷钱币、骰子、转轮、使用电子元件的噪音、核裂变等算法
伪随机数,经过必定算法和种子得出。软件实现的是伪随机数apache
强伪随机数,难以预测的随机数安全
弱伪随机数,易于预测的随机数服务器
随机数有3个特性,具体以下:网络
随机性:不存在统计学误差,是彻底杂乱的数列架构
不可预测性:不能从过去的数列推测出下一个出现的数框架
不可重现性:除非将数列自己保存下来,不然不能重现相同的数列
随机数的特性和随机数的分类有必定的关系,好比,弱伪随机数只须要知足随机性便可,而强位随机数须要知足随机性和不可预测性,真随机数则须要同时知足3个特性。
引起安全问题的关键点在于不可预测性。
伪随机数的生成
咱们日常软件和应用实现的都是伪随机数,因此本文的重点也就是伪随机数。
伪随机数的生成实现通常是算法+种子。
具体的伪随机数生成器PRNG通常有:
线性同余法
单向散列函数法
密码法
ANSI X9.17
比较经常使用的通常是线性同余法,好比咱们熟知的C语言的rand库和Java的java.util.Random类,都采用了线性同余法生成随机数。
应用场景
随机数的应用场景比较普遍,如下是随机数常见的应用场景:
验证码生成
抽奖活动
UUID生成
SessionID生成
Token生成
CSRF Token
找回密码Token
游戏(随机元素的生成)
洗牌
俄罗斯方块出现特定形状的序列
游戏爆装备
密码应用场景
生成密钥:对称密码,消息认证
生成密钥对:公钥密码,数字签名
生成IV: 用于分组密码的CBC,CFB和OFB模式
生成nonce: 用于防护重放攻击; 分组密码的CTR模式
生成盐:用于基于口令的密码PBE等
相比其余密码技术,随机数不多受到关注,但随机数在密码技术和计算机应用中是很是重要的,不正确的使用随机数会致使一系列的安全问题。
随机数的安全风险
随机数致使的安全问题通常有两种
应该使用随机数,开发者并无使用随机数;
应该使用强伪随机数,开发者使用了弱伪随机数。
第一种状况,简单来说,就是咱们须要一个随机数,可是开发者没有使用随机数,而是指定了一个常量。固然,不少人会义愤填膺的说,sb才会不用随机数。可是,请不要忽略我朝仍是有不少的。主要有两个场景:
开发者缺少基础常识不知道要用随机数;
一些应用场景和框架,接口文档不完善或者开发者没有仔细阅读等缘由。
好比找回密码的token,须要一个伪随机数,不少业务直接根据用户名生成token;
好比OAuth2.0中须要第三方传递一个state参数做为CSRF Token防止CSRF攻击,不少开发者根本不使用这个参数,或者是传入一个固定的值。因为认证方没法对这个值进行业务层面有效性的校验,致使了OAuth的CSRF攻击。
第二种状况,主要区别就在于伪随机数的强弱了,大部分(全部?)语言的API文档中的基础库(经常使用库)中的random库都是弱伪随机,不少开发天然就直接使用。可是,最重要也最致命的是,弱伪随机数是不能用于密码技术的。
仍是第一种状况中的找回密码场景,关于token的生成, 不少开发使用了时间戳做为随机数(md5(时间戳),md5(时间戳+用户名)),可是因为时间戳是能够预测的,很容易就被猜解。不可预测性是区分弱伪随机数和强伪随机数的关键指标。
固然,除了以上两种状况,还有一些比较特别的状况,一般状况下比较少见,可是也不排除:
种子的泄露,算法不少时候是公开的,若是种子泄露了,至关于随机数已经泄露了;
随机数池不足。这个严格来讲也属于弱伪随机数,由于随机数池不足其实也致使了随机数是可预测的,攻击者能够直接暴力破解。
wooyun上有不少漏洞,还蛮有意思的,都是和随机数有关的。
PS:我的实力有限,如下实例基本都来自wooyun漏洞实例,在这里谢谢各位大牛,若有侵权,请联系删除。
1.应该使用随机数而未使用随机数
Oauth2.0的这个问题特别经典,除了wooyun实例列出来的,其实不少厂商都有这个问题。
Oauth2.0中state参数要求第三方应用的开发者传入一个CSRF Token(随机数),若是没有传入或者传入的不是随机数,会致使CSRF登录任意账号:
惟品会帐号相关漏洞可经过csrf登陆任意帐号
人人网-百度OAuth 2.0 redirect_uir CSRF 漏洞
不少密码找回的场景,会发送给用户邮件一个url,中间包含一个token,这个token若是猜想,那么就能够找回其余用户的密码。
1.Shopex 4.8.5密码取回处新生成密码可预测漏洞
直接使用了时间函数microtime()做为随机数,而后获取MD5的前6位。
substr(md5(print_r(microtime(),true)),0,6);
PHP 中microtime()的值除了当前服务器的秒数外,还有微秒数,微妙数的变化范围在0.000000 -- 0.999999 之间,通常来讲,服务器的时间能够经过HTTP返回头的DATE字段来获取,所以咱们只须要遍历这1000000可能值便可。但咱们要使用暴力破解的方式 发起1000000次网络请求的话,网络请求数也会很是之大。但是shopex很是贴心的在生成密码前再次将microtime() 输出了一次:
$messenger = &$this->system->loadModel('system/messenger');echo microtime()." ";
2.奇虎360任意用户密码修改
直接是MD5(unix时间戳)
3.涂鸦王国弱随机数致使任意用户劫持漏洞,附测试POC
关于找回密码随机数的问题强烈建议你们参考拓哥的11年的文章《利用系统时间可预测破解java随机数| 空虚浪子心的灵魂》
CmsEasy最新版暴力注入(加解密缺陷/绕过防注入)
弱伪随机数被绕过
Espcms v5.6 暴力注入
Espcms中一处SQL注入漏洞的利用,利用时发现espcms对传值有加密而且随机key,可是这是一个随机数池固定的弱伪随机数,能够被攻击者遍历绕过
Destoon B2B 2014-05-21最新版绕过全局防护暴力注入(官方Demo可重现)
使用了microtime()做为随机数,能够被预测暴力破解
Android 4.4以前版本的Java加密架构(JCA)中使用的Apache Harmony 6.0M3及其以前版本的SecureRandom实现存在安全漏洞,具体位于classlib/modules/security/src/main /java/common/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java
类的engineNextBytes函数里,当用户没有提供用于产生随机数的种子时,程序不能正确调整偏移量,致使PRNG生成随机序列的过程可被预测。
Android SecureRandom漏洞详解
上面讲的随机数基础和漏洞实例更偏重是给攻击者一些思路,这里更多的是一些防护和预防的建议。
业务场景须要使用随机数,必定要使用随机数,好比Token的生成;
随机数要足够长,避免暴力破解;
保证不一样用处的随机数使用不一样的种子
对安全性要求高的随机数(如密码技术相关)禁止使用的弱伪随机数:
不要使用时间函数做为随机数(不少程序员喜欢用时间戳) Java:system.currenttimemillis() php:microtime()
不要使用弱伪随机数生成器 Java: java.util.Random PHP: rand() 范围很小,32767 PHP: mt_rand() 存在缺陷
强伪随机数CSPRNG(安全可靠的伪随机数生成器(Cryptographically Secure Pseudo-Random Number Generator)的各类参考
产生高强度的随机数,有两个重要的因素:种子和算法。算法是能够有不少的,一般如何选择种子是很是关键的因素。 如Random,它的种子是System.currentTimeMillis(),因此它的随机数都是可预测的, 是弱伪随机数。
强伪随机数的生成思路:收集计算机的各类信息,键盘输入时间,内存使用状态,硬盘空闲空间,IO延时,进程数量,线程数量等信息,CPU时钟,来获得一个近似随机的种子,主要是达到不可预测性