看各路神仙如何大戰MySQL insecure warning報警有感

沃趣科技發表於2017-06-06


看各路神仙如何大戰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 insecure warning報警有感

二、人間大炮一級準備:指令碼自己解決

最簡單的,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 insecure warning報警有感

三、人間大炮二級準備: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 --password

mysql --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 insecure warning報警有感

五、人間大炮發射:彙編解決

原始碼解決方案的問題在於需要維護自己的版本,每次MySQL新的版本釋出都需要重新打patch,並重新編譯。 

還有什麼其他的辦法列,Andrew McGill和Perry Harrington提供了在彙編層面解決這個問題的辦法!

5.1 刪除彙編中Warning資訊

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

  1. 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 Of

fset: 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 insecure warning報警有感

七、總結


MySQL出於安全的考慮,建議大家不要在命令列中寫password,但是隻是在命令列中提示,並且還不能關閉,確實比較坑,我們要做一個企業級的產品也需要對每一個細節和功能考慮的更加仔細和細緻,避免出現類似的問題。 

雖然官方也不知道啥時候能解決這個Warning的問題,但是各路大神各出奇招來解決這個問題,也給我們提供了很多思路,很有借鑑意義。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28218939/viewspace-2140329/,如需轉載,請註明出處,否則將追究法律責任。

相關文章