背景#
最近半路接手了一个系统的优化需求,这个系统有个遗留问题还没解决,随着新需求的上线,系统正式开放使用,这个遗留问题也必须解决。
这个系统大概是下面这样的,支持录入各种数据源的信息(ip、端口、数据库种类、账号密码等):
录入完成后,可以查看这些数据源中的表、表的ddl、表中的列(列名、类型及注释等),也可以查看各个表中的数据。
其中一个数据源,是sql server 2008版本,总是连接失败,更别提获取这个db中的表了。
错误堆栈如下:
定位过程#
1、前期处理#
在我做新需求的时候,我之前的同事A已经处理过这个问题。这个问题只在线上出现,因为开发测试环境压根没有这么老的数据库版本,在开发测试环境申请一台windows服务器来安装一个这样的老版本数据库,也比较麻烦;所以,同事A在处理的时候,基本是网上查到修改的办法后,直接弄到线上去试试能不能解决。
之前改过两次,第一次是这样:
1、参考附件脚本《配置文件java.security》,修改/usr/local/jdk/bin/java/java.security中的配置项jdk.tls.disabledAlgorithms。
修改内容:删除jdk.tls.disabledAlgorithms配置项的“TLSv1, TLSv1.1”,替换成“DHE”
简单解释下这部分的修改,从前文中的错误堆栈来看,这个问题是和ssl有关系的,我之前猜想的就是,这个sql server和mysql一样,支持使用tls加密传输,保护数据安全;但是,可能sql server 2008版本太老了,不支持tls 1.2/1.3这些,只能使用tls1.1/tls1.0等,但是呢,jdk认为使用tls1.1/1.0不够安全,默认是禁用了的,所以,只要把这个禁用tls1.1/tls1.0的配置给改改,允许jdk使用tls1.1/tls1.0,不就可以连接sql server 2008了吗?
但是,遗憾的是,这个改动之前已经上线试过了,没有生效,还是报错。
另外,在我做新需求的时候,同事A又试了一个改动,把驱动版本升级了下,大家知道java都是使用jdbc去连接数据源的,各个厂商会实现jdbc,之前呢,使用的是sqlserver的4.0版本的驱动,这把,直接弄到了8.4.1,准备搞上去再试试:
2、尝试修改配置禁用加密#
我了解到这个情况后,因为需求也比较赶,就没想花大力气来搞这个bug,我们都是内网服务器之间调用,这个加密传输,我感觉不是必要,直接弄成不加密不就行了吗?
我找了下代码,里面有拼接jdbc url的代码:
那直接去掉这个encrypt=true;trustServerCertificate=true
,去掉后,本地测试了下连接sql server数据库(不是2008版本),用wireshark抓包看了下,发现客户端发给数据库(sql server常用1433端口)的报文里,还是说加密是开启的:
行吧,我查了下,原来不指定encrypt属性,默认就是true,那我手动指定成false得了。
又抓包看了下,这次有了变化,客户端发过去的报文是说,不使用加密:
服务端返回报文也说,不加密: