從RPC協(xié)議看集權(quán)設(shè)施防護
RPC協(xié)議主要用來進行遠程過程調(diào)用,用一句話來概括,就是允許用戶程序調(diào)用服務器上的函數(shù)進行計算,由此實現(xiàn)兩者交互。
早先的企業(yè)環(huán)境中,所有的服務都在一臺主機上,就會導致服務器負荷過重,無法保證業(yè)務的正常運作。正因如此,后來企業(yè)就更換了一種思路,將不同服務分開,分別存放在不同主機上,暫時解決了負荷問題。但是久而久之,這樣的方式也開始顯現(xiàn)弊端,比如當用戶需要使用不同服務器上的服務協(xié)作來完成任務時,服務與服務之間該如何交互?
這就是RPC要解決的問題,簡言之,RPC可以允許一臺機器上的程序調(diào)用另一臺機器上的函數(shù),通過各計算機協(xié)作進行計算,以保證用戶任務順利完成
接下來我們詳細說說RPC的原理。
RPC原理
同AD域內(nèi)的大多數(shù)協(xié)議一樣,RPC也采用的是請求響應模式。通常的請求響應,只需要客戶端和服務器直接做交互就行了,但在RPC中,增加了兩個處理過程,即客戶端存根和服務器存根。
此存根的作用為:當客戶端想調(diào)用服務器上的某函數(shù)時,需要把客戶端的參數(shù)提供給服務器。而為了保證參數(shù)的保密、完整、可用和響應的高效性,客戶端需要對傳輸過程做些特殊處理,包括將數(shù)據(jù)序列化、封裝數(shù)據(jù)、尋址、傳遞數(shù)據(jù)等。
如果這一系列復雜行為都由客戶端來操作,將會耗時耗力,所以RPC就建立了一個存根,讓它來協(xié)調(diào)管理這些過程,減輕客戶端負擔。
在存根的作用下,客戶端將參數(shù)遞交給它,后續(xù)只需要等待接收服務器返回的數(shù)據(jù)就行了。因此,用戶其實是感受不到這個跟服務器交互的過程的,這一切似乎都像在本機上完成的一樣。
以上內(nèi)容,我們提到存根的一個重要作用——序列化。
所以,什么是序列化?
客戶端把參數(shù)交給存根后,如果存根直接將參數(shù)交給服務器,當服務器的系統(tǒng)與客戶端不一樣時,服務器就不能解析該參數(shù),也無法調(diào)用相應函數(shù),等于客戶端也就得不到正確的返回結(jié)果。
為了讓服務器能正確解析客戶端的參數(shù),我們就需要將參數(shù)轉(zhuǎn)化成服務器能理解的方式。
在RPC中,客戶端存根就把要傳遞的數(shù)據(jù)信息序列化成二進制,以方便服務器識別并處理。
這里的數(shù)據(jù)信息不單包括參數(shù),還有要調(diào)用的函數(shù)ID。客戶端存根將它們統(tǒng)一序列化成二進制后,打包遞交給傳輸層。
傳輸層使用TCP協(xié)議,所以RPC中,上層傳遞下來的二進制信息需要進一步封裝在TCP包中,尋址后發(fā)送給相應的服務器。
可都封裝好了,為什么要有尋址這一步驟呢?
簡而言之,尋址的重要作用就是找到該函數(shù)對應的服務器地址。但是企業(yè)環(huán)境中,各服務分散在不同的服務器上,如果都由客戶端來“記憶”,將導致巨大的資源浪費。為了方便查詢分散的服務地址,RPC中會將所有服務和對應地址都集中在一起,這個集中了所有服務地址的機器就是注冊中心。
通過注冊中心,客戶端和服務器可以更方便地交互。
對服務器來說,它每增加或注銷一項服務就通知注冊中心進行更改,而不必一一告知客戶端。對客戶端來說,它也不必記住每一項服務所在地址,也不用管服務地址是否有變化。只需要在申請服務時,從注冊中心查找到服務地址,向該地址發(fā)送數(shù)據(jù)包就行了。也就是說服務端的變化對客戶端幾乎沒有影響。
數(shù)據(jù)包傳遞到服務器后,先由傳輸層對其解析,得到序列化過的二進制包。
要把這個二進制包轉(zhuǎn)化成服務器能理解的數(shù)據(jù)格式,就需要與序列化相對的反序列化。
通常在服務器上,同樣擁有一個服務端存根,它和客戶端存根的作用一樣,用來管理RPC過程中的大部分事務,反序列化也由它來完成。
在這里,服務端存根對二進制包反序列化,得到參數(shù)和要調(diào)用的函數(shù)ID,然后遞交給服務器。服務器計算后得到結(jié)果,返回給客戶端。
RPC中,結(jié)果返回時,同樣需要服務端存根來對其進行序列化后傳輸,客戶端收到響應數(shù)據(jù)包后由客戶端存根再次對其反序列化,得到結(jié)果。
這樣,在RPC協(xié)議規(guī)范下,客戶端就成功調(diào)用了服務端的函數(shù)來完成計算。
結(jié)語
相比于HTTP等傳輸協(xié)議,RPC將數(shù)據(jù)序列化成二進制,直接在傳輸層上與服務端交互,極大地提高了傳輸效率。并且使用存根來管理RPC的底層過程,讓客戶端和服務端的交互變得透明,從而為用戶提供了方便。
不過,拋開傳輸效率的便利,RPC中同樣也存在很多安全威脅,比如Zerologon(CVE-2020-1472)、Printnightmare(CVE-2021-34527)等,攻擊者利用這些漏洞,可以直接通過RPC協(xié)議連接服務器,并向其發(fā)送惡意代碼,從而獲取控制目標服務器的權(quán)限,這也是使用協(xié)議時要提防的一個方向。