【Java代码审计】失效认证及不安全随机数篇

发布时间:2024年01月12日

【Java代码审计】失效认证及不安全随机数篇

1.不安全的随机数生成器

根据密码学原理,随机数生成器分为以下三类:

1、统计学伪随机数生成器(PRNG):伪随机数生成器从一个初始化的种子值开始计算得到序列,从种子开始,然后从种子中计算出后续值,当种子确定后生成的随机数也是确定的,但其输出结果很容易预测,因此容易复制数值流

2、密码学安全随机数生成器(CSPRNG):密码学安全伪随机性是统计学伪随机数生成器的一个特例,给定随机样本的一部分和随机算法,不能有效地演算出随机样本的剩余部分

3、真随机数生成器:其定义为随机样本不可重现。实际上只要给定边界条件,真随机数并不存在。可是如果产生一个真随机数样本的边界条件十分复杂且难以捕捉(比如计算机当地的本底辐射波动值),则可以认为用这个方法演算出来了真随机数

使用计算机产生真随机数的方法是获取CPU频率与温度的不确定性,以及统计一段时间内的运算次数每次都会产生不同的值,系统时间的误差以及声卡的底噪等。在实际应用中往往使用伪随机数就足够了。计算机或计算器产生的随机数有很长的周期性。实际上它们不真正地随机,因为它们是可以计算出来的,但是它们具有类似于随机数的统计特征。这样的发生器称为伪随机数发生器

Java中的“java.util.Random”工具类LCG线性同余法伪随机数生成器,可以根据种子和算法生成随机数。此算法的缺陷就是可预测性,攻击者可能会猜测将要生成的下一个值,并使用此猜测来模拟其他用户或访问敏感信息

在这里插入图片描述

java.util.Random”不是加密安全的。可以使用SecureRandom来获取密码安全的伪随机数生成器

在这里插入图片描述

使用SecureRandom生成伪随机,因为SecureRandom使用鼠标点击、键盘点击等等这些随机事件作为种子,故其生成的随机数列完全不同,安全性要高,所以建议使用“java.Security.SecureRandom”工具类来代替“java.util.Random”工具类


2.JWT弱加密

JSON Web Token 为开发人员提供了几种对有效负载声明进行数字签名的方法。这确保了数据完整性和强大的用户身份验证,每当开发人员使用 HMAC 签名时,他们都需要提供一个密钥,用于签名和验证令牌。如果这个密钥不够强大,整个签名可能会被泄露,造成越权操作等危害

漏洞代码:

// 设置了简单的密钥,可爆破从而进行伪造jwt
private static final String SECRET = "123456";
private static final String B64_SECRET = Base64.getEncoder().encodeToString(SECRET.getBytes(StandardCharsets.UTF_8));

public static String generateTokenByJjwt(String userId) {
    return Jwts.builder()
        .setHeaderParam("typ", "JWT")
        .setHeaderParam("alg", "HS256")
        .setIssuedAt(new Date())
        .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
        .claim("userid", userId)
        .signWith(SignatureAlgorithm.HS256, B64_SECRET)
        .compact();
}

通过破解JWT密钥啊,攻击者可以轻松获取当前的用户信息等:

在这里插入图片描述

防御方法:

确保使用强大的、不可预测的密钥来计算服务器上的 HMAC 签名。我们建议使用长度至少为 32 字节的随机生成值。

例如:

// 设置复杂的密钥
private static final String SECRET = "17245b290622c65bcc785ce3dd97dab3";

3.验证码复用

验证码反复利用,可以直接进行暴力破解

一般来说,验证码是与Session绑定的,Session生成时,也伴随着验证码的生成和绑定,在访问页面时,接口的请求和验证码的生成通常是异步进行的,这使得两个功能变得相对独立。也就意味着我们如果仅请求接口,而不触发验证码的生成,那么验证码就不会变化。 并且在考虑安全时,开发人员的关注点往往在 验证码校验是否通过,通过则进入业务流程,不通过则重新填写,而忽视了这个用户是否按照既定的业务流程在走(接口访问与验证码生成是否同时进行),验证码是否被多次使用了

例如,如下代码没有在用户鉴权失败时刷新验证码:

 // 未清除session中的验证码,导致可复用
 if (!CaptchaUtil.ver(captcha, request)) {
     model.addAttribute("msg", "验证码不正确");
     return "login";
 }

正确的方法是,不管验证码是不是输入正确,都应该及时销毁验证码

// 不管账号正确与否,一次请求后都清掉验证码
request.getSession().removeAttribute("captcha");
文章来源:https://blog.csdn.net/Gherbirthday0916/article/details/135551694
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。