看各路神仙如何大战MySQL insecure warning报警有感

一、问题由来

mysql在5.6.5上开始在命令行中直接填入用户密码会提示错误,例如:

$./mysql -h10.10.30.18 -uwoqutech -pwoqutech -ss -e 'select @@server_id'Warning: Using a password on the command line interface can be insecure.330618

如果你要写一个脚本调用mysql命令来获得server_id的值,这个Warning的信息绝对是你的噩梦。

提示这个安全原因本来无可厚非,但是坑爹的是,没有任何一个参数或者开关能关闭这个Warning。

2012年liu wei同学就提交了这个bug,到了2017年的今天,还是没有解决。期间有n多人开骂,其中Van Stokes骂的最经典:

How about this insane idea....
How about MySQL quits trying to save the world from itself and REMOVE THIS STUPID WARNING MESSAGE. It's NONE OF YOUR BUSINESS if I want to use a password on the command line or not. So quit worrying about it. Remove the warning. We don't need to be nannied to death by the likes of you.

翻译过来就是:

你们脑子秀逗了,赶紧把这个傻×报警信息清理掉,再不清理麻烦就大了!

骂归骂,也有很多人提供了对应的解决方案,甚至包括修改MySQL的汇编代码来解决。

二、人间大炮一级准备:脚本自己解决

最简单的,mysql自己不解决,我们脚本里面可以过滤。拿到这两行信息以后,通过grep -v或者各自程序语言去过滤掉这个错误信息。 但是每个脚本都需要有额外的逻辑来处理这个信息,也是大家非常不爽的原因。

Karl Nicoletti就很不爽:

Does the MySQL development team have ANY idea how many man-hours of work they have inflicted on DBAs and developers relying on command line input responses that DO NOT return the word "Warning" or "Error" in the case of successful execution???  I alone will be spending at least 100 hours to upgrade and test all our in-house maintenance, and installation scripts to work around this idiotic warning. Maybe, just MAYBE you could use the word "NOTE:" instead of "Warning:"??? Better yet, provide an option, --no-cmd-line-warning that would shut the damn thing off?

三、人间大炮二级准备:MYSQL_PWD,mysql_config_editor解决

还好,有一些其他的解决方案也可以解决这个问题。

mysql_config_editor

利用mysql_config_editor来保存用户名密码,避免输出Warning信息

mysql_config_editor set --login-path=woqutech --host=10.10.30.18 --user=woqutech --passwordmysql --login-path=woqutech  -e "select @@server_id"

这种方式必须手工输入密码,在脚本里面用也非常坑爹。

MYSQL_PWD

通过设置MYSQL_PWD变量来避免输出Warning信息

$MYSQL_PWD='woqutech' ./mysql  -h10.10.30.18 -uwoqutech  -ss -e 'select @@server_id'330618

这种方式相对接受度比较高。

四、人间大炮三级准备:源码解决

既然MySQL是开源的,那我们当然希望通过源码解决拉, 源码其实很简单

void print_cmdline_password_warning(){  static my_bool password_warning_announced= FALSE;  if (!password_warning_announced)  {    fprintf(stderr, "Warning: Using a password on the command line "            "interface can be insecure.\n");    (void) fflush(stderr);   password_warning_announced= TRUE;  }}

阿里的印风就提交了一个patch 供大家参考。

五、人间大炮发射:汇编解决

源码解决方案的问题在于需要维护自己的版本,每次MySQL新的版本发布都需要重新打patch,并重新编译。

还有什么其他的办法列,Andrew McGill和Perry Harrington提供了在汇编层面解决这个问题的办法!

5.1 删除汇编中Warning信息

Andrew McGill使用的是perl,解决方案如下

perl -p -i -e 's/(Warning: Using a password on the command line interface can be insecure..)/"\0"x(length($1))/es' /usr/local/mysql/bin/mysql

简单解释一下:

  • mysql程序编译出来就是一个汇编的代码
  • \0代表是空字符,"\0"x(length($1)表示多个空字符,不会打印任何字符
  • Andrew McGill利用perl将Warning: Using a password on the command line interface can be insecure.的信息都替换为空,也就不会打印Warning信息了。

5.2print_cmdline_password_warning函数逻辑修改

Perry Harrington提供了一种匪夷所思的汇编代码修改方式:

原版在测试环境下不可用:printf '\x75' | dd of=./mysql bs=1 seek=$((16#$(objdump --disassemble -F mysql |grep password_warning|grep je|awk '{print $1}'|cut -d: -f1|sed -e 's/^.//g'))) count=1 conv=notrunc
可用版本:printf '\xeb' | dd of=./mysql bs=1 seek=$((16#$(objdump --disassemble -F mysql |grep password_warning|grep jne|awk '{print $1}'|cut -d: -f1|sed -e 's/^.//g'))) count=1 conv=notrunc

这个需要解释一下

  • print_cmdline_password_warning函数中会判断password_warning_announced是否为FALSE,由于password_warning_announced是静态变量,再次进入这个函数将不会打印错误信息,函数代码如下:
  /** * This function should be called to print a warning message * if password string is specified on the command line. */

void print_cmdline_password_warning(){  static my_bool password_warning_announced= FALSE;

  if (!password_warning_announced)  {    fprintf(stderr, "Warning: Using a password on the command line "            "interface can be insecure.\n");    (void) fflush(stderr);    password_warning_announced= TRUE;  }}
  • 汇编代码中只需要把判断password_warning_announced的逻辑修改成直接跳转,就可以不打印出来了。

怎么修改列,通过objdump 可以查看到print_cmdline_password_warning函数的逻辑如下:

000000000044d980 <print_cmdline_password_warning> (File Offset: 0x4d980):  44d980:       55                      push   %rbp  44d981:       48 89 e5                mov    %rsp,%rbp  44d984:       53                      push   %rbx  44d985:       48 83 ec 08             sub    $0x8,%rsp  44d989:       80 3d e0 aa 59 00 00    cmpb   $0x0,0x59aae0(%rip)        # 9e8470 <_ZZ30print_cmdline_password_warningE26password_warning_announced> (File Offset: 0x5e8470)  44d990:       75 2f                   jne    44d9c1 <print_cmdline_password_warning+0x41> (File Offset: 0x4d9c1)  44d992:       48 8b 1d 07 00 4c 00    mov    0x4c0007(%rip),%rbx        # 90d9a0 <_DYNAMIC+0xd50> (File Offset: 0x50d9a0)  44d999:       48 8d 3d 40 c7 08 00    lea    0x8c740(%rip),%rdi        # 4da0e0 <special_opt_prefix_lengths+0x40> (File Offset: 0xda0e0)  44d9a0:       ba 49 00 00 00          mov    $0x49,%edx  44d9a5:       be 01 00 00 00          mov    $0x1,%esi  44d9aa:       48 8b 0b                mov    (%rbx),%rcx  44d9ad:       e8 26 df fb ff          callq  40b8d8 <fwrite@plt> (File Offset: 0xb8d8)  44d9b2:       48 8b 3b                mov    (%rbx),%rdi  44d9b5:       e8 ce e0 fb ff          callq  40ba88 <fflush@plt> (File Offset: 0xba88)  44d9ba:       c6 05 af aa 59 00 01    movb   $0x1,0x59aaaf(%rip)        # 9e8470 <_ZZ30print_cmdline_password_warningE26password_warning_announced> (File Offset: 0x5e8470)  44d9c1:       48 83 c4 08             add    $0x8,%rsp  44d9c5:       5b                      pop    %rbx  44d9c6:       c9                      leaveq  44d9c7:       c3                      retq  44d9c8:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)  44d9cf:       00

我们看到44d990行,上一行比较了password_warning_announced的值,jne表示不等于就跳转到函数尾44d9c1(退出堆栈),我们把汇编指令修改成无论如何都跳转jmp不就解决了这个问题吗?

 44d990:       75 2f                   jne    44d9c1 <print_cmdline_password_warning+0x41> (File Offset: 0x4d9c1)

所以修改的策略就是把jne修改成jmp,对应的就是要把75修改为eb。汇编指令操作码可以查考csdn

  • 75是jne
  • eb是jmp

所以最终的修改方式就是这么一个诡异的命令:

printf '\xeb' | dd of=./mysql bs=1 seek=$((16#$(objdump --disassemble -F mysql |grep password_warning|grep jne|awk '{print $1}'|cut -d: -f1|sed -e 's/^.//g'))) count=1 conv=notrunc
  • objdump –disassemble -F mysql |grep password_warning|grep jne|awk '{print $1}'|cut -d: -f1|sed -e 's/^.//g' 获得要修改的mysql汇编文件字节偏移位置
  • seek=$((16#$(objdump –disassemble -F mysql |grep password_warning|grep jne|awk '{print $1}'|cut -d: -f1|sed -e 's/^.//g'))) 获得16进制“要修改的mysql汇编文件字节偏移位置”
  • printf '\xeb' | dd of=./mysql bs=1 seek=$((16#$(objdump –disassemble -F mysql |grep password_warning|grep jne|awk '{print $1}'|cut -d: -f1|sed -e 's/^.//g'))) count=1 conv=notrunc 将mysql汇编文件中print_cmdline_password_warning函数中jne修改为jmp,直接跳转,不打印错误信息

七、总结

MySQL出于安全的考虑,建议大家不要在命令行中写password,但是只是在命令行中提示,并且还不能关闭,确实比较坑,我们要做一个企业级的产品也需要对每一个细节和功能考虑的更加仔细和细致,避免出现类似的问题。

虽然官方也不知道啥时候能解决这个Warning的问题,但是各路大神各出奇招来解决这个问题,也给我们提供了很多思路,很有借鉴意义。

原文发布于微信公众号 - 沃趣科技(woqutech)

原文发表时间:2017-06-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏木宛城主

基于Socket的网络聊天室编程(第一版)

一:什么是套接字 在网络编程中最常用的方案便是Client/Server (客户机/服务器)模型。在这种方案中客户应用程序向服务器程序请求服务。一个服务程序通常...

2545
来自专栏偏前端工程师的驿站

.Net魔法堂:log4net详解

一、作用                              提供一个记录日志的框架,可以将日志信息记录到文件、控制台、Windows事件日志和数据库(M...

2065
来自专栏Greenplum

Linux 常用命令(三)

curl 命令支持在线下载功能,使用方便,它支持,S,等协议,还支持PUT,POST,COOKIES,认证授权等操作。

1500
来自专栏Rainbond开源「容器云平台」

Docker源码分析之容器日志处理与log-driver实现

1473
来自专栏Golang语言社区

Golang测试技术

本篇文章内容来源于Golang核心开发组成员Andrew Gerrand在Google I/O 2014的一次主题分享“Testing Techniques”,...

3926
来自专栏更流畅、简洁的软件开发方式

【开源】QuickPager ASP.NET2.0分页控件 v2.0.0.2版本。

下载地址:http://files.cnblogs.com/jyk/Page2.0.0.2_080701.rar 这回只有 dll文件。请把包里的文件拷贝到...

1996
来自专栏分布式系统进阶

Kafka源码分析-启动流程

使用getPropsFromArgs方法来获取各配置项, 然后将启动和停止动作全部代理给KafkaServerStartable类;

1870
来自专栏*坤的Blog

公司web安全等级提升

公司的一个web数据展示系统,本来是内网的,而且是一个单独的主机,不存在远程控制的问题,所以之前并没有考虑一些安全相关的测试.但是国调安全检查的需要添加这样子的...

1694
来自专栏NetCore

Struts原理与实践

一、JDBC的工作原理 Struts在本质上是java程序,要在Struts应用程序中访问数据库,首先,必须搞清楚Java Database Connect...

2158
来自专栏落影的专栏

编译与链接过程的思考

前言 最近遇到一个错误,如下 ? 在解决过程中,回顾了很多知识,于是有了这篇文章。 关键词:预处理、编译、汇编、链接、动态链接库、静态链接库、真机调...

4929

扫码关注云+社区