CryptDB代碼分析1-lua與加密庫

之前的文章 ”CryptDB原理概述“ 介紹了CryptDB的基本原理,接下來從代碼的角度介紹其實現原理。本文首先關注mysql-proxy的lua腳本與CryptDB加密庫的交互過程。

前期準備

在進行源碼閱讀和調試之前,首先需要進行CryptDB的安裝。 之前已經對CryptDB在ubuntu 16.04上的安裝做過介紹。也可以使用我在github上共享的項目:https://github.com/yiwenshao/Practical-Cryptdb,里面對原始的安裝腳本做了小改,在ubuntu16.04只要執行INSTALL.sh 就可以完成全部的安裝工作。

安裝完成以后,首先執行如下的命令:

mkdir shadow
mysql-proxy --defaults-file=./mysql-proxy.cnf --proxy-lua-script=wrapper.lua

啟動mysql-proxy[1],然后就可以通過MySQL的客戶端連接mysql-proxy來完成數據庫操作。 所有SQL語句首先經過mysql-proxy的加密處理, 然后轉發給MySQL服務器。 對于MySQL服務器的返回結果, 也是先轉發給mysql-proxy, 經過解密處理以后返回給客戶端。

mysql-proxy通過lua腳本調用CryptDB的加密庫來完成SQL語句的加密操作,而上面建立的shadow目錄則是為了保存一個embedded模式的MySQL數據庫, 里面存儲了密鑰以及加密洋蔥的結構的等相關信息。

所以,接下來,我們先從lua腳本的入口出發,看一個SQL語句在加密過程中會經過哪些模塊。

mysql-proxy的與CryptDB的交互

mysql-proxy提供了如下幾個函數, 在客戶端執行SQL的不同階段, 會調用這幾個函數, 這些函數實現在 wrapper.lua 中:

  • read_auth()
  • disconnect_client()
  • read_query(packet)
  • read_query_result(inj)

在上面的四個函數的實現中,調用了CryptDB的加密庫中的幾個函數,這些函數實現在 mysqlproxy/ConnectWrapper.cc 中,分別是:

  • connect
  • disconnect
  • rewrite
  • next

所以,所有的CryptDB操作,都是以上面的8個函數為基礎的。對于CryptDB加密庫而言,里面的connect以及disconnect 只在客戶端建立連接和客戶端離開的時候被調用,所有的加解密功能都是通過rewritenext這兩個函數來完成,這兩個函數就是CryptDB所有功能的入口。

回到mysql-proxy的lua腳本中的四個函數,可以分以下三個階段來介紹。

客戶端建立連接

在這個階段,lua腳本中的函數read_auth被調用,其內部調用CryptDB的函數connect. 在這個階段,需要為每個客戶端建立一個WrapperState結構來保存相關的信息。不同的客戶端通過ip+port來標識,多個客戶端的信息則通過一個如下的map結構來進行保存:


std::map<std::string, WrapperState*> clients;

要使用加密庫,還需要進行適當的初始化,并且多個client之間有共享狀態。所以,如果當前連接進來的是第一個客戶端,則需要對這個共享狀態進行初始化,其對應的是一個變量:

SharedProxyState * shared_ps//多個client的共享狀態

客戶端離開

當客戶端關閉的時候,lua腳本中的disconnect_client函數被調用。其內部調用CryptDB的disconnect函數。這個階段會把map中保存的客戶端的信息刪除。

客戶端的命令執行流程

客戶端發送命令給mysql-proxy的時候,lua腳本中的read_query(packet)函數被調用,參數packet中包含了SQL命令。MySQL執行結果返回的時候,lua腳本中的read_query_result(inj)函數被調用,參數inj包含了返回結果。

  • 首先來看read_query函數。

當read_query 函數獲取到客戶端發送的明文SQL 命令的時候,會調用lua腳本中的read_query_real函數,其內部首先調用CryptDB庫中的rewrite函數,完成SQL語句的改寫。改寫后的SQL語句保存在之前介紹過的 clients 結構中。然后調用lua腳本中的next _handler 函數,其內部調用CryptDB庫中的next函數。在next函數中,首先執行函數獲得一個參數result_type,分為三種情況,根據不同的結果選擇不同的執行流程,包含了SQL命令執行的所有情況,分別如下:

//mysqlproxy/ConnectWrapper.cc

switch (result_type) {
    case AbstractQueryExecutor::ResultType::QUERY_COME_AGAIN: {
    //返回sql語句給lua腳本,執行結果再次進入該函數處理
    }
    case AbstractQueryExecutor::ResultType::QUERY_USE_RESULTS:{
    //返回sql語句給lua腳本,執行結果直接返回客戶端
    }
    case AbstractQueryExecutor::ResultType::RESULTS:{
    //返回解密結果給lua腳本,并由mysql-proxy返回給客戶端
    }
}

對于一般的SQL語句的執行,分為兩種情況,第一種是直接進入QUERY_USE_RESULTS分支,返回SQL語句給lua腳本,SQL執行的結果直接返回給客戶端。 第二種是進入第一個分支QUERY_COME_AGAIN,返回SQL語句給lua腳本轉發到MySQL執行,返回的結果再次進入next函數,執行并且進入第三個分支,返回解密的結果給客戶端。

另外,對于有些語句,并不需要調用rewrite函數進行加密,在lua腳本的階段直接過濾了,這些情況就更加簡單。

  • 然后來看read _query_results階段。

當上面介紹的加密SQL語句發送給MySQL執行,并返回執行結果給mysql-proxy的時候,會調用lua腳本中的read _query_results(inj)函數。如果在read_query階段進入了第二個分支,那么lua腳本會設置一個全局變量skip為true,read_query_results的處理就被跳過,直接返回結果給客戶端。如果在read_query階段進入了第一個分支,則會在這里再次調用next_handler函數,從而進入next函數,再次執行并進入switch分支的判斷流程。

兩個執行的例子

一些解密的細節以及類的介紹將在后續的文章中給出。在這里,給出兩個SQL語句執行的例子,用于說明執行過程中lua腳本以及CryptDB庫中的幾個函數的調用過程,以及幾個主要執行分支的含義。

  • show databases;

該命令的處理流程:
首先進入read_query,內部調用CryptDB的rewrite函數進行加密,然后調用lua中的next_handler,內部調用CryptDB的next函數,根據上面介紹的,進入switch的第二個分支,表示執行命令的結果不需要處理,直接返回給客戶端。然后給lua腳本傳遞改寫以后的命令。

再次回到lua腳本的next_handler函數,其處理了query results分支,將獲得的命令轉發給MySQL執行。執行完成以后的結果返回給mysql-proxy的時候,會調用read_query_result函數。根據上面介紹的,由于在read_query階段進入了第二個分支,這里的處理會被跳過,也就是不做任何處理,結果直接返回給客戶端。這樣,客戶端就得到了show databases的執行結果。

  • select * from student;

我們假設已經有了一張表,對其進行select操作,其對應的執行流程如下。
首先進入read_query,內部調用CryptDB的rewrite函數進行SQL語句的加密,返回以后調用lua中的next_handler函數,內部調用CryptDB的next函數,根據上面介紹的,進入第一個分支:QUERY_COME_AGAIN。返回加密以后的SQL命令給lua腳本。

在lua腳本中,next_handler處理了again分支,發送加密命令給MySQL,獲得select返回的加密結果以后,lua腳本中的read_query_results被調用。由于在read_query階段進入了第一個分支,這里會繼續調用next_handler函數,并進入到next函數,執行獲得result_type,然后這次進入到RESULTS分支。在lua腳本中,處理了results分支,將解密后的結果返回給客戶端,這樣就完成了整個流程。

總結

本文介紹了SQL加密執行過程中,mysql-proxy使用的lua腳本與CryptDB的加密庫的交互過程,其中主要的幾個函數是lua腳本中的read_query,read_query_results,以及CryptDB庫中的rewrite和next。代碼位于wrapper.lua以及mysqlproxy/ConnectWrapper.cc中。

參考文獻

原始鏈接:yiwenshao.github.io/2018/02/26/CryptDB代碼分析1-lua與加密庫/

文章作者:Yiwen Shao

許可協議: Attribution-NonCommercial 4.0

轉載請保留以上信息, 謝謝!

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Lua 5.1 參考手冊 by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,919評論 0 38
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,779評論 18 399
  • Nginx API for Lua Introduction ngx.arg ngx.var.VARIABLE C...
    吃瓜的東閱讀 5,876評論 0 5
  • 好不容易臨摹完心藍丫頭這幅花卉,說實話自己也沒看明白這朵花到底怎么個樣子,反正依葫蘆畫瓢臨摹下來了,自己覺得不難看...
    LindaC閱讀 343評論 0 0
  • 遙遠的山 有自己的故事 曾經的戀人 化成石頭變為永恒 遠古的樹 彌漫著神秘的顏色 是誰留下的 或許這就是傳說 遠方...
    長道赫書閱讀 169評論 16 6