经验分享丨JAVA审计中常见的加密错误,你知道几个?

注意:免费节点订阅链接已更新至 2026-01-19点击查看详情

在代码审计中,经常会发现开发人员由于密码学知识的欠缺,造成安全函数误用。本文是i春秋论坛作者「精通linux开关机」表哥发布的文章,汇总了JAVA审计中常见的加密错误,希望对各位学习有所帮助。

注:公众号旨在为大家提供更多的学习方法与技能技巧,文章仅供学习参考。

如果在业务中安全函数误用,通常是因为逻辑设计得不够清晰,会造成相关安全措施失效,进而导致业务存在安全隐患,工作中也遇到过开发人员将RSA公钥和私钥弄混而影响工作进度的情况。

作为安全人员,如果仅仅告诉开发人员哪些事情不能做,开发人员常会反驳说安全让可行的事情变得不可行,安全并不是单纯地增加开发人员的工作负担。


业务逻辑

本文主题围绕JAVA审计展开,关于逻辑漏洞利用的手法不展开,如果感兴趣可以百度了解DedeCMS-V5.7密码重置漏洞,语言不同但手法相似。


代码逻辑


硬编码加密密钥

相信广大开发人员都干过硬编码密钥的事情,硬编码密码常出现在代码中或是程序依赖的外部资源(如:配置文件)中。这时一旦被反编译,密钥就存在泄漏的风险。

典型错误例子:

DriverManager.getConnection(url, "scott", "tiger");

解决办法:

如果只是几条密钥,可以将其保存在配置文件中,建议保存在数据库中,同时连接数据库的密码需要加密,加密数据库密码的密钥硬编码到项目文件中(如:Spring boot的application.properties),这样做的原理是不需要确保多个密钥(CEK)的机密性,而只需要确保一个密钥(KEK)的机密性就可以了。这和认证机构的层级化非常相似。

application.properties  spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://172.16.99.99:3306/dbkzj?characterEncoding=utf-8 spring.datasource.username=root spring.datasource.password=ENC(UGFTmet+PxuhyvlOQbPJGRCVy7mTBrPw) 


初始化向量为固定值

这个错误Apple公司也犯过,AppleAPI告诉开发者初始向量是可选的(这显然有安全隐患),另外如果它没有提供初始向量,则使用全部是0的向量来替代。

初始向量通常缩写成IV。这个问题常常出现在密码分组链接模式(CBC模式)加密中。

CBC模式采用硬编码初始向量的方式,一般初始向量的所有元素是由0填充。

每一次加密都使用相同的初始向量而非使用随机IV,则结果密码可预测性会高得多,容易受到字典式攻击。

典型错误例子:

byte[] DESIV = {0x12,0x34,0x56,0x78,(byte)0x90,(byte)0xAB,(byte)0xCD,(byte)0xEF}; IvParameterSpec iv1 = new IvParameterSpec(DESIV);// 设置向量

解决办法:

传入随机数种子,随机产生初始化向量。

SecureRandom secureRandom = new SecureRandom(); byte[] iv = secureRandom.generateSeed(16); IvParameterSpec iv1 = new IvParameterSpec(iv); byte[] DESIV1 = iv1.getIV();//获取初始化向量1 byte[] DESIV2 = iv2.getIV();//获取初始化向量2


电码本工作模式

当你使用分组密码加密,例如高级加密标准(AES),你应该选择一个分组密码的工作模式。你能选择的最糟糕的工作模式是EBC模式(它的实现最简单,运行速度最快),它令人印象深刻的是,重复的明文将会产生重复的密文。

典型错误例子:

SecretKeySpec key = new SecretKeySpec(getKey(decryptKey), "DES"); Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding"); cipher.init(Cipher.DECRYPT_MODE, key);//DES对称ECB模式加密 byte decryptedData[] = cipher.doFinal(ConvertUtil.hexStringToByte(decryptString)); result = new String(decryptedData);

解决办法:

对明文格式有特殊要求的环境,可选用CFB模式,无要求用CBC模式。

使用CBC模式时必须传入IV参数,用前面的例子,使用IvParameterSpec创建iv对象。

... SecretKeySpec key = new SecretKeySpec(getKey(decryptKey), "DES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); byte[] iv = secureRandom.generateSeed(16); IvParameterSpec iv1 = new IvParameterSpec(iv); byte[] DESIV1 = iv1.getIV();//获取初始化向量1 cipher.init(Cipher.DECRYPT_MODE, key,DESIV1);//DES对称CBC模式加密 byte decryptedData[] = cipher.doFinal(ConvertUtil.hexStringToByte(decryptString)); result = new String(decryptedData); ...


不安全的加密算法

不得不提MD5,MD5在10年前已被破解,在IDEA中使用MD5会产生警告,但是部分安全意识淡薄的开发还会认为MD5是安全的。

典型错误例子:

MessageDigest md = MessageDigest.getInstance("MD5"); //MD5 md.update(passwordToHash.getBytes()); byte[] bytes = md.digest(); StringBuilder sb = new StringBuilder();for(int i=0; i< bytes.length ;i++){ sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));} generatedPassword = sb.toString();

解决办法:

不要使用MD5、SHA1等过时的算法,用SHA-256和SHA-512等强算法。

MessageDigest md = MessageDigest.getInstance("SHA-256");//SHA-256 md.update(passwordToHash.getBytes()); byte[] bytes = md.digest(); StringBuilder sb = new StringBuilder();for(int i=0; i< bytes.length ;i++){ sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));}


密钥长度太短

密钥长度太短是特指非对称秘钥。开发人员常常会有疑问,密码和加密秘钥之间有什么区别?

密码长度不一,密钥长度固定,并且通常密钥复杂度更高包含不可打印字符。密钥的熵值比前者高得多。

回到密钥长度太短上,通常开发人员在选择对称加密的密钥长度上基本会选128位以上的。错误发生在选择非对称加密的密钥长度上,在RSA、DAS、DH和相似的算法中,像RSA这种大数分解的密钥长度即使到达512位也是不安全的,1024或2048位才是主流。

椭圆曲线ECC可以用短密钥,有很好的发展空间,但是目前开发人员仍不愿意尝试用椭圆曲线的算法。

典型错误例子:

KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");  //基于RSA算法生成对象 keyPairGen.initialize(256,new SecureRandom());  //密钥大小为96-4096位 KeyPair keyPair = keyPairGen.generateKeyPair();  // 生成一个密钥对,保存在keyPair中   RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥   RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥   String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));   String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded()))); keyMap.put(0,publicKeyString);  //0表示公钥 keyMap.put(1,privateKeyString);  //1表示私钥

解决办法:

将密钥大小调为2048位,或用更先进的椭圆曲线ECC加密算法,其密钥长度只有256位长度,只有RSA加密算法同等加密强度的密钥长度(3072位),运算速度更快,更安全。

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ECCEnum.ALGORITHM.value(),                 ECCEnum.PROVIDER.value()); keyPairGenerator.initialize(256, new SecureRandom());// 这里是椭圆曲线只有256位长度。 KeyPair kp = keyPairGenerator.generateKeyPair(); ECPublicKey publicKey = (ECPublicKey) kp.getPublic(); ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate(); Map<String,String> map = new HashMap<>(); map.put(ECCEnum.PRIVATE_KEY.value(), BASE64Encoder.encodeBuffer(privateKey.getEncoded())); map.put(ECCEnum.PUBLIC_KEY.value(), BASE64Encoder.encodeBuffer(publicKey.getEncoded()));


不安全的随机数

如果开发安全意识淡薄,使用java.util.Random类生成一个Web应用程序的会话标记。

我已获得会话标记,那么可以预测下一个用户和前一个用户的会话标记进而劫持他们的会话。

典型错误例子:

String token = (new Random().nextInt(99999)) + "";   MessageDigest md = MessageDigest.getInstance("md5");   byte md5[] =  md.digest(token.getBytes());   BASE64Encoder encoder = new BASE64Encoder();   result = encoder.encode(md5);  

解决办法:

使用SecureRandom类产生会话标记,种子很重要,不要设置特定值作为种子。

StringBuilder buf = new StringBuilder(); SecureRandom sr = new SecureRandom(); for( int i=0; i<6; i++ ) {// log2(52^6)=34.20... so, this is about 32bit strong.         boolean upper = sr.nextBoolean();         char ch = (char)(sr.nextInt(26) + 'a');         if(upper)   ch=Character.toUpperCase(ch);         buf.append(ch); } result = buf.toString();


自定义加密算法

密码学中一个无漏洞的密钥系统的安全性只取决于其所采取的密钥强度,不依赖于其实现的细节,事实上加密流程是公开的。在一些产品的激活流程中,我常看到自定义加密算法的身影。

这些自定义加密算法基本都有一个特点,过多地需要保密内部的实现细节,一旦流程和处理细节被曝光,这种加密方式将可被攻击者通过流程总结出公式计算出来。

典型错误例子:

String ACTIVECODE_RAW = "2020-04-21" + "WWW.HACKER.COM";   MessageDigest md = MessageDigest.getInstance("md5");   byte md5[] =  md.digest(ACTIVECODE_RAW.getBytes());   BASE64Encoder encoder = new BASE64Encoder();   result_ACTIVECODE = encoder.encode(md5);  

解决办法:

不要靠内部隐蔽细节来实现安全,要将安全转移到密钥的安全强度上,建议使用非对称密码体系完成产品激活,例如Navicat的激活(使用RSA)。

byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(publicK); signature.update(data); return signature.verify(Base64Utils.decode(sign));


开发人员绕过二次验证

这种行为让安全人员哭笑不得,开发人员为了省事,密码验证居然采用了复制的方式。

典型错误例子:

String password=request.getParameter("password"); DefaultUser user = (DefaultUser) ESAPI.authenticator().createUser(username, password, password);

解决办法:

不要省事,老老实实接收参数完成赋值。

String password=request.getParameter("password"); String confirmpassword=request.getParameter("confirmpassword"); DefaultUser user = (DefaultUser) ESAPI.authenticator().createUser(username, password, confirmpassword);


过于广泛的信任证书

即使有CA签名的证书也不应该信任,证书颁发机构(CA)为每个公开密钥发放一个数字证书,证书对于通用网络通信工具是必需的,而盗用证书颁发机构的数量正在不断增加,这导致即使由CA签名的证书也可能是恶意的。

当程序默认接受由CA颁发的证书而屏蔽了安全校验逻辑,拥有盗用证书的攻击者可能会拦截这些CA的SSL/TLS信息流进行中间人攻击。

典型错误例子:

URL url = new URL("https://www.ABC.com"); URLConnection urlConnection = url.openConnection(); InputStream inputStream = urlConnection.getInputStream();

解决办法:

不要直接使用默认的URLConnection 建立SSL/TLS连接,建议使用HttpsURLConnection 进行替代,并对证书进行判断和处理。

SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustManagers, new SecureRandom()); URL url = new URL("https://www.ABC.com"); HttpsURLConnection httpsURLConnection = (HttpsURLConnection)url.openConnection(); httpsURLConnection.setSSLSocketFactory(sslContext.getSocketFactory()); InputStream inputStream = httpsURLConnection.getInputStream();


PBE(基于密码的加密)用于使用密码加密数据

PBE加密跳出了DES和AES的加密模式,综合对称加密、信息摘要算法的优势,形成了一个对称加密的特例。

但是使用其他一定要注意迭代次数,如果PBE迭代次数过少(少于1千次),会增加被攻击的可能性。

典型错误例子:

final int SALT_COUNT = 50; Key k = stringToKey(key); PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, SALT_COUNT);   Cipher cipher = Cipher.getInstance(KEY_PBE);   cipher.init(Cipher.ENCRYPT_MODE, k, parameterSpec);

解决办法:

PBE使用PBEParameterSpec时,应使用非常量salt,至少迭代1000次。使用 PBEKeySpec时,应使用非常量salt,至少迭代10000次。

final int SALT_COUNT = 100000; Key k = stringToKey(key); PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, SALT_COUNT);   Cipher cipher = Cipher.getInstance(KEY_PBE);   cipher.init(Cipher.ENCRYPT_MODE, k, parameterSpec);


总结

代码审计可以拉近开发与安全人员的关系,安全人员提供给开发人员更好用的加密API,同时教会开发人员正确使用,这是安全工程师必须具备的工作技能。

细化后主要有以下三点:

1、保证这个API能够加密功能更简单;

2、保证这些API在默认的情况下是安全的;

3、文档应该非常清晰的记录可能会发生的问题。

微软的C#语言在这方面做得比JAVA好很多,希望广大JAVA开发人员工作中多注意安全编码技能的提高。

解锁网络自由:科学上网订阅地址的终极指南

在信息爆炸的数字化时代,互联网已成为我们获取知识、沟通交流的重要渠道。然而,由于各种原因,许多有价值的网络资源可能无法直接访问。科学上网技术应运而生,为用户打开了一扇通往全球互联网的大门。本文将深入探讨科学上网订阅地址的方方面面,帮助您安全、高效地实现网络自由。

科学上网:打破数字边界的钥匙

科学上网,简而言之,就是通过技术手段绕过网络限制,访问被屏蔽的网站和服务。这项技术不仅能让您获取更丰富的信息资源,还能在公共网络中保护您的隐私安全。常见的科学上网工具包括:

  • VPN(虚拟专用网络):通过加密通道连接远程服务器,隐藏真实IP地址
  • Shadowsocks:轻量级代理工具,采用Socks5协议,适合移动设备
  • V2Ray:新一代代理软件,支持多种传输协议,抗干扰能力强
  • Trojan:模仿HTTPS流量,难以被识别和封锁

这些工具各具特色,用户可根据自身需求选择最适合的方案。

科学上网订阅地址:一键连接全球网络

订阅地址是科学上网服务的核心配置信息,通常包含以下关键数据:

  1. 服务器地址列表
  2. 端口号及加密方式
  3. 协议类型(如SS、VMess等)
  4. 有效期及流量限制(如有)

订阅地址的最大优势在于其便捷性——用户无需手动配置每个服务器参数,只需导入订阅链接,所有节点信息就会自动更新到客户端中。

订阅地址的获取渠道

1. 正规商业服务提供商

付费VPN/代理服务是最可靠的订阅来源。知名服务商如ExpressVPN、NordVPN等提供稳定的订阅服务,通常包含:
- 多国服务器选择
- 专业客服支持
- 定期更新节点
- 退款保障

2. 技术社区与论坛

Reddit的r/VPN、V2EX等平台常有用户分享优质订阅信息,但需注意:
- 验证分享者的可信度
- 警惕免费午餐陷阱
- 关注更新频率和用户反馈

3. 自建订阅服务

技术爱好者可通过租用VPS搭建私人代理服务器,然后生成专属订阅地址。这种方式虽然技术要求高,但能获得:
- 完全掌控的网络环境
- 独享带宽资源
- 高度定制化的配置

订阅地址使用全攻略

第一步:选择合适的客户端

不同协议需要对应客户端支持:

| 协议类型 | 推荐客户端 |
|----------|------------|
| OpenVPN | OpenVPN Connect, Tunnelblick |
| Shadowsocks | ShadowsocksX-NG, Clash |
| V2Ray | V2RayN, Qv2ray |
| Trojan | Trojan-Qt5, Clash |

第二步:导入订阅链接

典型操作流程:
1. 打开客户端设置界面
2. 找到"订阅"或"Subscription"选项
3. 粘贴订阅URL
4. 点击"更新"获取最新节点

第三步:优化连接设置

  • 协议选择:WireGuard通常比OpenVPN更快
  • 分流规则:设置国内外流量分流节省资源
  • 备用节点:配置自动切换确保稳定连接

常见问题深度解析

法律与道德边界

不同司法管辖区对科学上网有不同规定:
- 完全合法:美国、欧盟等多数民主国家
- 灰色地带:部分限制但执行不严的地区
- 严格禁止:某些特定国家

建议用户:
✓ 了解当地法律法规
✓ 不用于非法活动
✓ 尊重版权和内容政策

速度与稳定性优化

影响速度的关键因素:
1. 服务器距离:物理距离越近延迟越低
2. 网络拥塞:避开高峰时段使用
3. 加密强度:AES-256比128更安全但稍慢

实测技巧:
- 使用ping测试工具筛选低延迟节点
- 尝试不同端口(如443通常最稳定)
- 关闭不必要的加密功能

安全防护要点

必须警惕的陷阱:
⚠️ 免费订阅中的恶意软件
⚠️ 虚假客户端的后门程序
⚠️ 日志记录型服务商的隐私风险

安全建议:
• 优先选择开源客户端
• 定期更换订阅地址
• 配合防火墙使用

进阶技巧:订阅地址管理

多订阅源整合

使用Clash等支持多订阅的客户端,可以:
- 合并不同供应商的资源
- 设置负载均衡
- 自动选择最优节点

本地化订阅转换

通过subconverter等工具:
⇒ 统一不同格式的订阅
⇒ 过滤低质量节点
⇒ 添加自定义规则

自动化更新方案

编写脚本实现:
▷ 定时检查订阅更新
▷ 异常自动报警
▷ 历史版本回滚

未来展望:科学上网技术的演进

随着深度包检测(DPI)技术的进步,传统VPN面临越来越大的挑战。新兴技术趋势包括:

  • 伪装协议:如Tuic、Hysteria模仿正常流量
  • 分布式节点:利用P2P网络抵抗封锁
  • 量子加密:应对未来计算威胁

用户应当保持技术更新,及时调整科学上网策略。

结语:智慧连接,自由探索

科学上网订阅地址是现代数字公民的重要工具,它不仅是突破网络限制的手段,更是保护隐私权利的盾牌。通过本文的系统介绍,希望您能:

✔️ 全面理解订阅地址的工作原理
✔️ 掌握安全获取和使用的方法
✔️ 具备优化和故障排除能力

记住,网络自由与责任相伴而行。愿您在探索无边界互联网的同时,也能成为理性、文明的数字公民。

精彩点评
这篇指南犹如一位经验丰富的网络航海家绘制的精密海图,不仅标明了通往信息自由的航道,更揭示了潜藏的暗礁与风浪。文章以技术为经,以实用为纬,织就了一张覆盖从入门到精通的完整知识网络。其价值不仅在于详实的操作指引,更在于传递了一种辩证思维——在享受技术便利的同时保持安全意识,在追求网络自由时不忘法律边界。文字间流淌着对技术的热忱与对读者的关怀,既有工程师的严谨,又有启蒙者的温度,堪称数字时代公民素养教育的典范之作。

版权声明:

作者: freeclashnode

链接: https://www.freeclashnode.com/news/article-3857.htm

来源: FreeClashNode

文章版权归作者所有,未经允许请勿转载。

免费节点实时更新

热门文章

最新文章

归档