看這個題目,大家肯定會有疑惑:什麼叫web應用頁面關係?聽我慢慢來解釋。
在現有的web應用中,可展示的網頁數量要要大於實際的JSP檔案的個數,原因是在處理事件或者單純的頁面跳轉時,URL後面會帶有一些參數,例如:
http://XXXXXXXX:9090/linghao/buy.jsp?action=add&iid=2 處理這些URL的頁面不一定位於一個新的JSP檔案,可能在自身檔案就內部處理了,所以說可展示的網頁數量要大於實際的JSP檔案數目。今天我們關心的重點在這些參數上,不同的參數個數和參數值都會導致當前頁面跳轉到不同的頁面,這些頁面的關係資訊往往都隱藏於JSP的java代碼中,除非你手動的去找,否則只能通過程式分析的方法把這些參數找出來。
現在有一個相關工作做了類似的分析《Improving Test Case Generation for Web Applications Using Automated Interface Discovery》
這個工作也是通過分析servlet來找domain infomation也就是URL後面的參數資訊,只不過這個工作當時是用在測試方面,為了更多的覆蓋執行路徑,跟我們要解決的問題屬於同一類,先看看他們的解決方案是什麼。
他們先定義了一個example servlet:(IP表示input parameters)
interface = IP∗IP = name, domain informationname =< string >domain information = domain type, relevant value∗domain type = ANY |NUMERICrelevant value =< string > | < number >
文章提到了一個演算法,主要分兩步:
一、找到參數的類型string OR number......
Algorithm 1 – Phase1/* GetDomainInfo */Input: servlets: set of servlets in the web application //JSP檔案中的JAVA代碼Output: ICFG: ICFG for the servlets, annotated with domain information //輸出JAVA代碼的標有參數資訊的過程間控制流程圖begin ICFG ← ICFG for the web application //首先得到過程間控制流程圖 compute data-dependence information for the web application for each PFcallintheservlets do//對每一處出現request.getParameter();進行處理 PFnode ← ICFG’s node representing PF PFvar ← lhs of the PF call statement //request.getParameter()的傳回值 newannot ← new annotation //添加註釋 newannot.IPnode ← PFnode//注釋內容-Node newannot.type ← ANY//初始化類型為任意 newannot.values ← {}//可能的值集合為空白 associate newannot with PFnode //把這些注釋標記到當前分析的node節點 GDI(DUchain(PFvar, node), PFvar, PFnode, {}) 調用GDI的函數,具體實現在下面,DUchain代表define-use鏈 end for return ICFG /* returns annotated ICFG */end/* GDI */Input: node: current node to examine //參數一:需要分析的NodeIPvar: variable storing the IP value and used at node //參數二:在node處使用的代表參數值的變數root node: node to be annotated//參數三:需要添加註釋的節點visited nodes: nodes visited along current path//參數四:用以做標示的變數,若節點被分析過就標為visited,防止再次分析begin if node !∈ visited nodes then//如果node沒有被分析過 if node is an exit node then//如果是一個函數的退出語句 returnsites ← possible return sites for node’s method //該函數退出後可能返回的節點集合,也就是當初調用此函數的節點結合 for each retsite ∈ returnsites do //對於每個調用node所在方法的節點 retvar ← variable defined at retsite//記錄node所在方法執行完成後的傳回值 newannot ← root node’s annotation//並把node所在方法的根節點方法的注釋記錄下來 associate newannot with node retsite//建立注釋與node的聯絡 GDI(DUchain(retvar, retsite), retvar, retsite,visited nodes ∪ {node})//遞迴調用GDI函數,DUchain(v,n)表示在n出定義的v變數被使用的節點集合 end for else if node represents a comparison with a constant then//如果使用變數時是比較操作 compval ← value used in the comparison//把被用來比較的值記錄下來 addValueToAnnotation(root node, compval)//把這個值添加在root節點的注釋中 else if node is a type cast/conversion of IPvar then//如果使用變數時是類型轉換操作 casttype ← target type of the cast operation//把轉換後的類型記錄下來 setDomainTypeInAnnotation(root node, casttype)//把注釋中的類型欄位改成轉換後的類型 end if if node contains a definition of a variable then//如果node處包含一個新的變數定義,也就是說如果之前的變數使用在把值傳給另一個變數的情況下 var ← variable defined at node for each n ∈ DUchain(var, node) do//需要再跟蹤這個變數,一直要找到從參數取下來的值最後到底轉換成了什麼類型以及有哪些可能的值 GDI(n, var, root node, visited nodes ∪ {node}) end for end if end if end ifend
其實這個演算法完成的主要工作就是來確認URL中參數的類型以及它們可能的數值,演算法的輸出如
演算法的第二步:得到可能的參數組合
Algorithm 2 – Phase 2/* ExtractInterfaces */Input: ICFG: annotated ICFG produced by GetDomainInfo//第一步得到的過程間控制流程圖Output: interfaces[]: interfaces exposed by each of the servlets//可能跳轉到的頁面集合begin CG ← call graph for the web application//擷取web應用的調用圖,圖的節點是方法 SCC ← set of strongly connected components in CG//找到其中的強連通部分 SINGLETONS ← set of singleton sets, one for each node in CG that is not part of a strongly connected component//出去強連通部分的節點集合 CC ← SCC ∪ SINGLETONS//所有的節點集合 for each mset ∈ CC, in reverse topological order do //對每個節點(方法)按照逆拓撲序遍曆,即先遍曆底層的函數,這樣保證在分析時函數所有函數調用的其他方法都有分析結果 SummarizeMethod(mset)//具體的方法實現在下面 end for return interfaces of each servlet’s root methodend /* SummarizeMethod */Input: methodset ⊂ CG nodes: singleton set or set of strongly connected methods in the call graph//mset是一個強連通方法集合或者單個方法 begin N ← Sm∈methodset nodes in m′s CFG worklist ← {} for each n ∈ N do //便利m的控制流程圖內的每個節點 In[n]← {}//進入n的變數集合初始為空白 if n corresponds to a PF call then //如果n是一個request.getParameter()這樣的操作 newIP ← new IP newIP.node ← n newIP.name ← parameter of the PF call //儲存PF方法的參數,也就是request.getParameter()的參數,即URL中傳遞的參數的名稱 if n’s annotation has domain information dominfo then newIP.domaininfo ← dominfo//如果n包含URL資訊(演算法第一步的結果),則把這個資訊添加到新的IP中 else newIP.domaininfo ← null end if Gen[n] ← {{newIP}} //因為產生了一個新節點,所以把新節點加入Gen[n]集合 add nodes in succ(n) to worklist//把n後面的節點加入到要分析的列表中 else if n is a callsite AND target(n) has summary s then //如果n這個節點調用了別的方法並且調用的方法已包含summary Gen[n] ← map(n, s) //n處就產生了一個新的節點和summary的對應關係 for each interface ∈ Gen[n] do //遍曆Gen集合中的每個節點 for each IP ∈ interface do annot ← annotation associated with n’s return site if IP.node == annot.IPnode ANDannot has domain information dominfo then IP.domaininfo ← dominfo end if end for end for add nodes in succ(n) to worklist else if n is a method entry point then//如果n是一個方法進入點,那麼它不會產生IP Gen[n] ← {{}} add nodes in succ(n) to worklist else Gen[n]← ∅ end if Out[n] ← Gen[n] end for while |worklist| 6= 0 do n ← first element in worklist In[n]← Sp∈pred(n) Out[p] Out′[n] ← {} for each i ∈ In[n] do for each g ∈ Gen[n] do Out′[n] ← Out′[n] ∪ {i ∪ g} //列出可能產生的IP組合 end for end for if Out′[n] 6= Out[n] then Out[n] ← Out′[n] if n is a callsite AND target(n) ∈ methodset then add target(n)’s entry node to worklist else add nodes in succ(n) to worklist end if end if end while for each m ∈ methodset do summary ← Out[m’s exit node]//方法m退出節點的IP輸出集合就是要求的summary associate summary to method m for each interface ∈ summary do for each IP ∈ interface such that IP.name is not a concrete value do IP.name ← resolve(IP)//把虛參換成對應的實參 end for end for end forend
演算法第二步先是對調用流圖中的各集合中的方法體進行遍曆,對每個方法都產生一個summary包含各種可能的IP組合。
這兩個演算法篇幅比較長,是文獻裡提到的,研究明白也花了很長時間,特此拿來記錄一下,鞏固記憶也協助想解決這個問題的童鞋,收工,睡覺去~