1糟糕透顶的明文配置
在web安全领域,黑客常常利用web应用的漏洞,将攻击脚本(webshell)上传至服务器,便可以获得一个与web应用具有相同权限的控制权限。但是很多公司直接给web应用ROOT权限,致使黑客在渗透突破的第一步就获取到了最高权限,这是一种非常不安全的做法,当然权限管理不是本文主题,这里就不做过多的讨论了。黑客在攻破一个web服务器后决不会就此罢手,会开展进行一步的渗透攻击,黑客的最终目的是获得数据,因此web应用连接数据库等一些数据服务的配置信息,就会成为黑客第一时间要收集的信息。然而,很多多公司的web配置文件全部采用明文的方式进行配置,使得数据库连接地址,账号密码等一览无余,具体配置如下:
遇到这样的系统,黑客一旦获取web权限,便可以不费吹灰之力得到mysql数据库的权限,我相信很多网站都是这样去进行数据库连接信息配置的,是极其不安全的。那应该怎么办?如果我们能将关键的配置信息进行加密处理,就能大大增加黑客直接获取到数据库连接信息的难度。本文基于Spring Boot项目来介绍一个第三方的用于配置文件加密保护的项。
2初探 Jayspt
首先我们先来看一下利用jayspt后,DataSource的可以达到的配置效果,如下图所示:
相对于本文第一张配置,我们将DataSource的数据库连接的配置都由明文都变成了密文的形式,并且采用了base64进行编码。关于编码,这里说句题外话,作者在实际工作中很多程序员分不清编码,加密,哈希这三个概念,在系统设计描述时经常概念混用让人摸不着头脑,这里有必要科普一下相关概念:
- 加密(Encrypt):是将明文与秘钥通过加密算法进行运算后得出密文,一般分为对称与非对称加密,对称加密(AES,DES,BLowfish等)采用同一秘钥进行加解密操作;非对称加密(RSA、ECC椭圆曲线加密算法)又叫做公私钥加密,采用一对公私秘钥进行加解密,由于公钥加密的密文只有私钥可以解密,因此公钥可以在网络中传播,系统只要保护好私钥,密文就不会存在被破解的风险,而对称加密在实际应用中就需要考虑秘钥安全问题了。虽然非对称加密更安全,但是其计算性能远不如对称加密,因此并不适用于大量数据的加密,在实际中,往往是在秘钥协商环节采用非对称加密来保护对称加密秘钥的传输,数据的加密依旧采用对称加密技术。
- 哈希(Hash):首先说明一点Hash与加密最大的不同是Hash是不可逆的。Hash又称之为信息摘要,可以唯一表示某一信息。在实际应用中,Hash一般应用在密码与数据完整性校验的场景,一般来说Hash应该具有再其表示空间内的不可碰撞性,不可碰撞性是说A的Hash一定结果是B,B一定是A的HASH结果,不可能是C的HASH结果。关于Hash这里有一个误区,很多同学发现网络上存在一些Hash破解的网站,就认为Hash是可以逆还原,这是错误的观点,网络中提供的Hash破解是通过彩虹表进行Hash碰撞进行破解的(原理就是将大量常用的明文密码Hash,构建彩虹表,如果需要破解的Hash在彩虹表中,那也就得知了Hash前的原始信息,从而实现了破解,一句话Hash可破解,但不可逆),常见的Hash算法有MD4、MD5、SHA-1等。
- 编码(Encoder):编码是一个复杂的概念,但所有编码的目的都是为了数据可以适应当前的环境下存储或传输的需求。编码与加密不是一个概念,编码不具备信息保护的能力,编码是一种信息表述转换的技术。例如在某些场景下,不可见字符的传输有可能会被截断,那就需要进行编码,在完成传输后再按照一定的规则进行解码,便可还原了原始的信息,不会造成数据的丢失。
好了,我们继续本文的主题,jayspt 正是使用了Base64对加密后的二进制密文进行编码,从而解决了配置文件无法配置二进制信息的问题。通过jayspt加密处理后的配置信息相对明文配置就安全多了,大大提高了黑客获取数据库连接信息的难度。下面我们来看看项目中使用jayspt的具体方法。
3Jayspt的使用
首先我们需要在工程中引用jayspt库,这里我们是使用gradle构建的spring-boot项目,相关引用如下:
然后就可以引用jayspt库,来生成加密字符串了,这里我们队数据库的连接信息进行加密,得到加密后的密文:
得到加密后的密文后就可以按照图2的方式进行DataSource的配置了(见前文中配置方式)。此外,还需要用加密用的秘钥配置给jayspt,使得jayspt可以正确解密配置信息,jayspt配置如下:
最后,不要忘记通过 @EnableEncryptableProperties 注解开启Spring Boot项目对于jayspt加密配置文件的支持。
4Jayspt自定义加密策略
在配置文件中需要被解密的属性需要被ENC()包裹的后才能被jayspt识别,到目前为止虽然我们的配置信息可以不用明文的方式存储了,但是如果黑客熟悉jasypt,在结合我们配置的jasypt解密密码,同样可以轻易的解密出我们加密的信息,因此jasypt支持配置我们自定义的加解密方式,从而提高了黑客解密配置信息的难度,我们需要提供一个StringEncryptor 类型的Bean,并命名为jasyptStringEncryptor,此时我们就能在Bean中配置相对应的加解算法,密码,编码方式等信息,如下所示:
此时我们就可以将配置文件中jasypt的相关配置删除了。这里还需要注意一点,我们需要使用配置的StringEncryptor进行的加密,否则配置信息将无法被jayspt解密。关于加密方式,jayspt采用了JCE(Java Cryptography Extension),默认采用SunJCE中的PBEWithMD5AndDES加密方式来加密,在项目中可以根据实际需要来配置jayspt的加密方式。
5替换ENC标签
ENC()是jayspt默认的用于标记配置值需要解密的标签,如果我们使用ENC,有经验的黑客还是很有可能一眼判断出我们使用了jayspt进行加密,jayspt对于自定义解析标签的配置提供了支持,如下:
这样,在配置文件中就能使用$JWTK{}来代替ENC()进行密文的包裹了,使得我们的配置具有一定的迷惑性。但是如果直接在配置文件中设置jayspt的行为,还是过多暴露了配置文件所采用的加密技术,为了更加隐蔽,我们可以实现一个EncryptablePropertyDetector 来进行解密标签的配置,如下:
同时需要为jayspt提供名为encryptablePropertyDetector的Bean:
OK,这样在配置文件中就没有Jayspt的踪迹了。
6Spring框架下的通用配置加密思路
上文介绍了jayspt这一个专用于解决配置加密问题的第三方java包,已经可以大大的提高网站配置文件的安全性了,可以满足一般网站的配置文件安全的需求了。介于目前Spring Boot在实际市场上的采用率还不是那么高的情况下,作者这里针对目前大多数SSH框架下依旧采用的通过xml来配置Spring的实情,给出一种简易的配置文件加密的解决思路。Spring框架最为强大之处就在于其IOC模型,开发者可以可以根据实际情况来实现java对象的装配与管理,这也使得java的开发成为了面向接口开发的最佳实践。利用装配的思路,可以实现了一个String 类型的FactoryBean,用来做读取加密字符串和解密的操作,然后通过Spring依赖配置将其注入到DataSource对应的配置中,便实现了配置信息的解密与装配,实际配置文件如下:
在Spring的配置中JwtkDecryptor便是我们实现了FactoryBean接口的String类型对象工厂,在Spring对DataSource中的依赖注入进行装填时便会调用JwtkDecryptor的getObject()接口来获取一个String类型的对象,因此我们在该函数中实现了数据的解密就可以保证Spring将解密后的String对象注入到了DataSource对应的属性中。相信读者可以通过结合上图Spring Bean的装配配置,不难理解整个依赖注入的整个流程,这里只给出JwtkDecryptor的关键代码:
7更多的思考
采用上面的技术,web配置信息就真的安全了吗,问题就都解决了吗?
面对如今黑客的逆向技术的发展,java的反编译技术早已不是什么难事(JD-GUI),黑客通过逆向分析项目采用的加密技术,便可以开发出对应解密工具,同样可以获取到web的相关配置。但不要沮丧,因为从来没有绝对安全的系统,妄图通过一项技术就解决所有安全问题也是不可能的,这里作者想起来当年学习逆向技术时《 加密与解密 》一书中所阐述反调试技术应用时的观点,没有一项反调试技术可以防止软件被调试,但是软件可以通过多种反调试技术相结合来增加软件被破解的难度。本文中提到的多种策略也是意在提高系统被破解的门槛,这个门槛越高,我们的系统相对来说就越安全。此外,关于加解密,我们可以将其放到更底层中去实现,例如在C++中实现一个加解密的动态链接库,并通过JNI接口的方式在java中调用,这样就极大的提高了系统加密的安全性,但也同时提高了系统开发的难度与运行风险,一方面是大多Java程序员并不熟悉C++开发,因此增加了系统代码开发的难度,另一方面是需要保证动态链接库的绝对稳定,因为动态链接库一旦崩溃,便会导致整个java进程的崩溃,从而增加了java项目的运行风险。但即便如此,作者还是在最近的一个项目中采用了这样的技术来对配置文件与上层协议提供加解密的保护,为了系统安全,这些都是值得的。
小结
本文从java web的角度讨论了应用程序配置信息安全保护的问题,意在提高开发人员对于关键系统配置信息的安全保护意识,并不局限加密,例如可以对jar包混淆,使用classloader内存加载加解密模块等技术。在信息保护的手段中,往往让人意想不到的策略才是好的策略。