本文的實驗都假設PHP模塊已經安裝在了Apache Web服務器上了,并且被放在了目錄 /chroot/httpd下。除此以外,我們還作了如下的假設:
MySQL數據庫僅被同主機上的PHP使用;
默認的管理工具像mysqladmin、mysql和 mysqldump,被用來管理數據庫。另外,遠程的數據備份將使用SSH協議執行。
為了獲得更高的安全性能,對于MySQL的安裝和配置,應該與以下的安全要求相符合:
1) MySQL數據庫應該在被改變了默認根目錄的環境下運行;
2) MySQL進程必須使用一個在系統進程中唯一的UID/GID;
3) 對MySQL的訪問僅限于本地;
4) 保證MySQL根賬戶的密碼不易被猜測;
5) 禁止對數據庫的匿名訪問;
6) 刪除系統自帶的所有的示例數據庫和表;
安裝MySQL
在我們開始加強MySQL的安全性之前,必須在服務器上安裝它。我們在操作系統上來創建一個組和用戶帳號,并使之唯一,使之與MySQL數據庫相關聯,方法如下:
|
1.編譯MySQL
我們先來在目錄/usr/local/mysql下編譯和安裝MySQL軟件:
|
總的來說,在Apache服務器上安裝MySQL的過程基本上與手動安裝等同。可能唯一的不同點就是使用了一些參數而已,像指定了./configure行。這里最重要的不同點在于參數“--with-mysqld-ldflags=-all-static”的使用,它可以使MySQL服務器使用靜態連接。就像在第三部分涉及到的其他參數一樣,這將顯著簡化改變服務器的根路徑的過程,它們通知make程序安裝在目錄/usr/local/mysql下,以mysql賬戶的權限運行MySQL的后臺程序,并且在/tmp目錄下創建mysql.sock套接字。
2.拷貝配置文件
在執行了上面的命令后,我們還必須拷貝默認的配置文件以與期望的數據庫大小一致。例如:
|
3.啟動服務器
到這里為止,MySQL已經完全安裝了,并且整裝待發了。我們可以通過執行下面的命令來啟動MySQL的服務器:
|
4.測試連接
嘗試與一個數據庫建立連接:
|
如果連接成功,系統將顯示如下內容:
|
然后,我們就可以看看本機上有哪些數據庫,如下所示:
|
2 rows in set (0.00 sec)
然后退出當前命令,使用如下命令:
|
一旦連接成功建立,我們就可以通過如下命令關閉數據庫:
|
如果不這樣做,我們就應該分析一下存儲在 /usr/local/mysql/var/`hostname`.err日志文件中的信息的安全性,以消除導致問題的因素。
改變服務器的默認根目錄
接下來的第一步就是準備chrooted環境,以使MySQL服務能夠運行。這里的目標操作系統是FreeBSD4.7。然而,本文中所講授的方法同樣適用于大多數的UNIX和類似UNIX的系統。
1.準備chroot環境
為了準備chrooted環境,我們必須創建如下的目錄:
|
2.設置訪問權利
上面對目錄的訪問權利應該如下設置:
|
3.創建目錄結構
接下來,下面的這些文件應該拷貝到新的目錄中:
|
4.強化密碼和組
我們必須從文件/chroot/mysql/etc/passwords和/chroot/mysql/etc/group里刪除除了賬戶和組以外的行,接下來,還應該按照如下方法build密碼數據庫:
|
5.特殊考慮
在Apache Web服務器上,我們還必須創建一個特殊的設備文件/dev/null:
|
系統將顯示如下的信息:
|
然后,我們再使用如下的命令:
|
我們還必須拷貝那些包含著在MySQL安裝過程中創建的包含授權表的mysql數據庫:
|
6.本地化
如果主機上使用的默認語言不是英語,我們還應該拷貝合適的字符集,可以在目錄/usr/local/mysql/share/mysql/charset下找到。
7.測試配置
現在,MySQL應該可以在chrooted環境中運行了。我們可以通過下面這個命令來驗證一下它是否能正確的運行:
|
如果在執行了上面的命令后出現了錯誤,我們應該使用truss命令或者具有等價功能的命令如:ktrace/kdump、strace等等。這些命令可以幫助我們來找出和消除引起問題的原因。
(腳本小子:這里為了能夠運行mysqld進程,使用的是chrootuid程序而不是chroot程序,因為假設是在Apache或者PHP的環境下,它們兩個的主要不同在于chrootuid可以改變執行進程的所有者,在我們的例子里面,mysqld在一個chrooted環境下被執行的,但是進程的所有者不是root而是mysql用戶,Chrootid在許多操作系統里并不是默認安裝的,需要我們從網上下載下來,然后手動安裝上去,可以到網址[url]ftp://ftp.porcupine.org/pub/security/chrootuid1.3.tar.gz[/url]下載。)
配置服務器
接下來的步驟,我們就要來配置數據庫服務器,使之能夠適合我們的安全性要求。
在假定MySQL進行默認安裝的時候,主要的配置文件是/etc/my.cnf。然而,在我們的例子里,因為是在chrooted環境下運行服務,所以我們就要使用兩個配置文件/chroot/mysql/etc/my.cnf和/etc/my.cnf。其中,前一個可以被MySQL服務器使用,而后一個要被MySQL工具(如mysqladmin,mysql,mysqldump等)使用。
1.禁止遠程訪問
我們知道,MySQL默認情況下使用TCP的3306端口,所以,我們首先要改變一下。因為,按照我們開始的設想,數據庫僅僅是讓本機的PHP應用程序訪問,所以,我們可以將這個監聽端口的功能禁止掉。這樣就可以降低MySQL數據庫遭受直接經由TCP/IP訪問的外部主機攻擊的可能性。而同時,本地的交互還可以通過mysql.sock套接字進行。為了能夠禁止在3306端口上監聽,我們要將參數skip-networking添加到/chroot/mysql/etc/my.cnf目錄下[mysqld]部分。如果在有的時候還需要從外部訪問數據庫,可以按照如下方法使用SSH協議:
|
2.提高本地安全性
接下來,為了防止對本地文件進行未授權的訪問,我們還需要禁止掉對LOAD DATA LOCAL INFILE命令的使用。這對于有效防止當在PHP應用程序中發現了新的SQL注入漏洞是非常有效的。這里,我們需要對在目錄/chroot/mysql/etc/my.cnf下的[mysqld]部分加一個參數set-variable=local-infile=0。
另外,為了更方便的使用數據庫管理工具,我們還必須改變/etc/my.cnf目錄[client]部分的參數設置為socket = /chroot/mysql/tmp/mysql.sock。這樣,當我們以后再需要用到管理工具的時候,就不用每次都來使用帶有socket=/chroot/mysql/tmp/mysql.sock參數的命令了。
3.改變管理員的密碼
在加強MySQL安全性的這些步驟里,改變管理員的密碼是很重要的一步,但是,這首先需要MySQL運行起來,可以通過如下命令實現:
|
用下面的命令改變管理員的密碼:
|
(腳本小子:不要直接在命令行里改變密碼,如使用“mysqladmin password”命令,因為這就有可能被同時使用服務器的其他用戶看到,從而泄漏密碼。例如:其他用戶可以使用“ps aux”命令或者查看歷史文件,就可以看到我們設置的密碼。)
4.刪除默認的數據庫和用戶
接下來,我們必須刪除示例數據庫和除了root賬戶以外的所有的賬戶,可以使用如下命令來實現:
|
這就可以有效阻止對數據庫的匿名連接和清除在/chroot/mysql/etc/my.cnf下的與skip-networking無關的參數,從而阻止遠程連接。
5.改變管理員的登陸名稱
我們同樣也推薦將默認管理員的賬戶名稱修改,這樣,就可以使得外部用戶很難猜測賬戶名稱。這樣一個改變,就可以有效的阻止對管理員密碼的暴力攻擊和字典攻擊。因為,攻擊者首先要猜出用戶名稱,然后才能猜測密碼。可以通過如下方式改變:
|
6.刪除歷史紀錄文件
最后,我們應該將MySQL中歷史文件的內容刪除,因為所有執行過的SQL命令都被以明文的形式存儲在這里,很容易泄密。這可以通過如下方式實現:
|
如何在PHP和MySQL之間進行交互
因為本地的PHP與MySQL之間的交互通過/tmp/mysql.sock套接字進行,而將PHP放在chrooted環境中意味著它們之間不能交互。為了解決這個問題,在我們每次使用MySQL的時候,都必須先創建一個到PHP的chrooted環境的穩固連接。這可以通過如下命令實現:
|
(腳本小子:/chroot/mysql/tmp/mysql.sock套接字和/chroot/httpd/tmp目錄必須處在相同的文件系統下,否則他們之間的穩固連接將不能正常工作。)
現在,我們要創建能夠被指定的PHP應用使用的所有的數據庫和賬戶,需要注意的是,這些帳戶僅僅擁有通過PHP應用對數據庫進行訪問的權利。特別需要指出的就是,這些帳戶不應該具有對mysql數據庫訪問的任何權力,當然更不用說對系統的訪問和管理特權(FILE, GRANT, ALTER, SHOW DATABASE, RELOAD, SHUTDOWN, PROCESS, SUPER 等)了。
最后,我們也應該創建一個shell腳本,用來在啟動系統的時候來運行MySQL,可以到[url]http://www.securityfocus.com/unix/images/mysql.sh[/url]上下載,而在我們的FreeBSD系統里,上面的腳本應該放在/usr/local/etc/rc.d目錄下,取名為mysql.sh。
好了,大功告成,通過上面的設置,如果有人想通過mysql入侵你的服務器,估計不死都得掉層皮,嘿嘿!
采用上面陳述的方法,我們可以顯著提高MySQL的安全性。通過在一個chrooted環境下運行數據庫,禁止掉對TCP3306端口的監聽,采用強壯的用戶密碼,我們就可以使數據庫免受大多數的攻擊。雖然沒有方法能夠使我們得到100%的安全性,但是使用描述的方法,至少可以降低來自訪問我們的Web服務的用戶的不明目的攻擊的可能性。
(T114)