作为一个DBA,帮助应用化解系统层面疑难点,始终是我们的责任。这次就遇到到了密码加解密的问题。
一、JAVA+MYSQL常用的加解密方法
大家知道,我们在进行JAVA开发的时候,如果要进行密码加密解密,常规方式是在MVC中的M(模型)或者C(控制层)中,对密码字段进行加密,例如。常用的加密形式如下:
public void setHostUserPasswd(String hostUserPasswd)
{
DesEncrypterIsmp t = new DesEncrypterIsmp();
this.hostUserPasswd = t.encrypt(hostUserPasswd);;
}
读取的时候,java代码中读取密码,然后进行解密:
host_User_passwd = t.decrypt(host_User_passwd);
实现中大家稍微差异,但原理都大同小异。
看上去没有任何问题,但在复杂项目中,例如使用多语言编程的项目中,就存在问题了,往下看。
二、使用JAVA加解密存在问题
1、普遍使用网上提供的加解密函数,函数封装度较高,自己没有指定私钥。这其实是很危险的,大家下载了一个公用的加解密函数,私钥是内置的,反正功能实现了,也懒得去改。
2、多语种编程,难以解密。用java加密的密码,用其它语言就很难解密,这相当于重写一次解密函数,例如,这次遇到了,前台用java,后台用python,解密函数要重写。
根据java中的解密函数,本人用python试了几天,也没有正确把密码解密出来,怀疑同样的函数,内部处理不一样,无奈放弃。寻找其它代价小的方案。
三、使用MYSQL内置加解密函数,化解上述尴尬
使用AES_ENCRYPT+TO_BASE64(加密+编码)的方式,轻松实现数据库层密码加解密。
有的人可能会说,就是个编码,不是加密,注意看,TO_BASE64是编码,AES_ENCRYPT可是加密函数。它们对应的解密函数是:aes_decrypt(解密)+from_base64(反编码)
使用方法如下:
3.1加密
用AES_ENCRYPT+TO_BASE64,SQL如下:
select TO_BASE64(AES_ENCRYPT('Thisismypasswd','xxxxx'))
期中,Thisismypasswd是明文密码,xxxxx是秘钥,秘钥和都很关键,且建议90天更新一次。
运行后:F99KEYHO6f9fznO+ZbDHTQ==
3.2解密
使用from_base64 +aes_decrypt进行解密:
select aes_decrypt(from_base64 ('F99KEYHO6f9fznO+ZbDHTQ=='),'xxxxx')
注意,xxxxx密码要配置,这很关键。
运行后:Thisismypasswd
四、在开发项目中使用
只需要在项目的SQL控制部分,将上述函数及秘钥写入,即可实现“SQL级别密码加解密”,例如,在java的xml 的中,对SQL控制片段增加相关短语即可,加密示例:
<if test="hostUserPasswd != null and hostUserPasswd != ''">TO_BASE64(AES_ENCRYPT(#{hostUserPasswd},'xxxxx')),</if>
1、在python项目中,在执行密码获取的SQL中,直接将相关密码解密,传递给验证函数即可。
2、在java项目中,需要原来代码做少量改动。JAVA代码的改动量极小,只是在密码读取与存储时,将原来的加解密函数去掉即可,在SQL部分完成加解密。
当然,这样做,要考虑一个问题,就是密码在传输过程中,是否是密文的。要解决这个问题,最好使用https进行传输。
不要以为传统的就是加密传输的:即使你用传统的JAVA加解密方法,加解密的java函数也是在服务器端完成的,如果传统的方式是加密传输的,那这种方式也是。
但,如果要验证,还是建议抓包分析,还是要谨慎。
再强调一遍吧,用HTTPS,用HTTPS,用HTTPS,当然,这与本文无关。