程式碼審計--9--Java web基礎
一 Java語言基礎
Request & Response(請求與響應)
請求和響應在Web開發當中沒有語言之分不管是ASP、PHP、ASPX還是JAVAEE也好,Web服務的核心應該是一樣的。在我看來Web開發最為核心也是最為基礎的東西就是Request和Response!我們的Web應用最終都是面向使用者的,而請求和響應完成了客戶端和伺服器端的互動。伺服器的工作主要是圍繞著客戶端的請求與響應的。
二 JavaWeb架構
1、瞭解MVC
傳統的開發存在結構混亂易用性差耦合度高可維護性差等多種問題,為了解決這些毛病分層思想和MVC框架就出現了。MVC是三個單詞的縮寫,分別為: 模型(Model),檢視(View) 和控制(Controller)。 MVC模式的目的就是實現Web系統的職能分工。
Model層實現系統中的業務邏輯,通常可以用JavaBean或EJB來實現。
View層用於與使用者的互動,通常用JSP來實現(JavaWeb專案中如果不採用JSP作為展現層完全可以沒有任何JSP檔案,甚至是過濾一切JSP請求)。
Controller層是Model與View之間溝通的橋樑,它可以分派使用者的請求並選擇恰當的檢視用於顯示,同時它也可以解釋使用者的輸入並將它們對映為模型層可執行的操作。
Model1和Model2:
Model1主要是用JSP去處理來自客戶端的請求,所有的業務邏輯都在一個或者多個JSP頁面裡面完成,這種是最不科學的。舉例:http://localhost/show_user.jsp?id=2。JSP頁面獲取到引數id=2就會帶到資料庫去查詢資料庫當中id等於
Model1的流程:
Model 2表示的是基於MVC模式的框架,JSP+Servlet。Model2已經帶有一定的分層思想了,即Jsp只做簡單的展現層,Servlet做後端的業務邏輯處理。這樣檢視和業務邏輯就相應的分開了。例如:http://localhost/ShowUserServlet?id=2。 也就是說把請求交給Servlet處理,Servlet處理完成後再交給jsp或HTML做頁面展示。JSP頁面就沒必要去關心你傳入的id=2是怎麼查詢出來的,而是怎麼樣去顯示id=2的使用者的資訊(多是用EL表示式或JSP指令碼做頁面展現)。檢視和邏輯分開的好處是可以更加清晰的去處理業務邏輯,這樣的出現安全問題的機率會相對降低。
MVC模式同樣被廣泛用於Java的各種框架中,比如Struts2、spring MVC等等都用到了這種思想
2、Web.xml作用
每個javaEE工程中都有web.xml檔案,那麼它的作用是什麼呢?它是每個web.xml工程都必須的嗎?
一個web中可以沒有web.xml檔案,也就是說,web.xml檔案並不是web工程必須的。web.xml檔案是用來初始化配置資訊:比如Welcome頁面、servlet、servlet-mapping、filter、listener、啟動載入級別等。
當你的web工程沒用到這些時,你可以不用web.xml檔案來配置你的Application。
每個xml檔案都有定義它書寫規則的Schema檔案,也就是說javaEE的定義web.xml所對應的xml Schema檔案中定義了多少種標籤元素,web.xml中就可以出現它所定義的標籤元素,也就具備哪些特定的功能。web.xml的模式檔案是由Sun 公司定義的,每個web.xml檔案的根元素為<web-app>
中,必須標明這個web.xml使用的是哪個模式檔案。如:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
</web-app>
web.xml的模式檔案中定義的標籤並不是定死的,模式檔案也是可以改變的,一般來說,隨著web.mxl模式檔案的版本升級,裡面定義的功能會越來越複雜,標籤元素的種類肯定也會越來越多,但有些不是很常用的,我們只需記住一些常用的並知道怎麼配置就可以了。
下面列出web.xml我們常用的一些標籤元素及其功能:
1、指定歡迎頁面,例如:
<welcome-file-list>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index1.jsp</welcome-file>
</welcome-file-list>
PS:指定了2個歡迎頁面,顯示時按順序從第一個找起,如果第一個存在,就顯示第一個,後面的不起作用。如果第一個不存在,就找第二個,以此類推。
關於歡迎頁面:
訪問一個網站時,預設看到的第一個頁面就叫歡迎頁,一般情況下是由首頁來充當歡迎頁的。一般情況下,我們會在web.xml中指定歡迎頁。但 web.xml並不是一個Web的必要檔案,沒有web.xml,網站仍然是可以正常工作的。只不過網站的功能複雜起來後,web.xml的確有非常大用處,所以,預設建立的動態web工程在WEB-INF資料夾下面都有一個web.xml檔案。
2、命名與定製URL。我們可以為Servlet和JSP檔案命名並定製URL,其中定製URL是依賴命名的,命名必須在定製URL前。下面拿serlet來舉例:
(1)、為Servlet命名:
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>org.whatisjava.TestServlet</servlet-class>
</servlet>
(2)、為Servlet定製URL、
<servlet-mapping>
<servlet-name>servlet1</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
3、定製初始化引數:可以定製servlet、JSP、Context的初始化引數,然後可以再servlet、JSP、Context中獲取這些引數值。
下面用servlet來舉例:
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>org.whatisjava.TestServlet</servlet-class>
<init-param>
<param-name>userName</param-name>
<param-value>Daniel</param-value>
</init-param>
<init-param>
<param-name>E-mail</param-name>
<param-value>[email protected]</param-value>
</init-param>
</servlet>
經過上面的配置,在servlet中能夠呼叫getServletConfig().getInitParameter(“param1”)獲得引數名對應的值。
4、指定錯誤處理頁面,可以通過“異常型別”或“錯誤碼”來指定錯誤處理頁面。
<error-page>
<error-code>404</error-code>
<location>/error404.jsp</location>
</error-page>
-----------------------------
<error-page>
<exception-type>java.lang.Exception<exception-type>
<location>/exception.jsp<location>
</error-page>
5、設定過濾器:比如設定一個編碼過濾器,過濾所有資源
<filter>
<filter-name>XXXCharaSetFilter</filter-name>
<filter-class>net.test.CharSetFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>XXXCharaSetFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
6、設定監聽器:
<listener>
<listener-class>net.test.XXXLisenet</listener-class>
</listener>
7、設定會話(Session)過期時間,其中時間以分鐘為單位,假如設定60分鐘超時:
<session-config>
<session-timeout>60</session-timeout>
</session-config>
3、JavaWeb Servlet和Filter
可以說JavaWeb和PHP的實現有著本質的區別,PHP屬於解釋性語言.不需要在伺服器啟動的時候就通過一堆的配置去初始化apps而是在任意一個請求到達以後再去載入配置完成來自客戶端的請求。ASP和PHP有個非常大的共同點就是不需要預先編譯成類似Java的位元組碼檔案,所有的類方法都存在於*.PHP檔案當中。而在Java裡面可以在專案啟動時去載入配置到Servlet容器內。在web.xml裡面配置一個Servlet或者Filter後可以非常輕鬆的攔截、過濾來自於客戶端的任意字尾請求。在系列2的時候就有提到Servlet,這裡再重溫一下。
Servlet配置:
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>org.javaweb.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/servlet/LoginServlet.action</url-pattern>
</servlet-mapping>
Filter配置:
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Filter在JavaWeb當中用來做許可權控制再合適不過了,再也不用在每個頁面都去做session驗證了。假如過濾的url-pattern是/admin/*那麼所有URI中帶有admin的請求都必須經過如下Filter過濾:
Servlet和Filter一樣都可以攔截所有的URL的任意方式的請求。
其中url-pattern可以是任意的URL也可以是諸如*.action萬用字元。既然能攔截任意請求如若要做引數和請求的淨化就會非常簡單了。servlet-name即標註一個Servlet名為LoginServlet它對應的Servlet所在的類是org.javaweb.servlet.LoginServlet.java。由此即可發散開來,比如如何在Java裡面實現通用的惡意請求(通用的SQL注入、XSS、CSRF、Struts2等攻擊)?敏感頁面越權訪問?(傳統的動態指令碼的方式實現是在每個頁面都去加session驗證非常繁瑣,有了filter過濾器,便可以非常輕鬆的去限制目錄許可權)。
上面貼出來的過濾器是Struts2的典型配置,StrutsPrepareAndExecuteFilter過濾了/*,即任意的URL請求也就是Struts2的第一個請求入口。任何一個Filter都必須去實現javax.servlet.Filter的Filter介面,即init、doFilter、destroy這三個介面,這裡就不細講了,有興趣的朋友自己下載JavaEE6的原始碼包看下。
public void init(FilterConfig filterConfig) throws ServletException;
public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException;
public void destroy();
TIPS:
在Eclipse裡面看一個介面有哪些實現,選中一個方法快捷鍵Ctrl+t就會列舉出當前介面的所有實現了。例如下圖我們可以輕易的看到當前專案下實現Filter介面的有如下介面,其中SecFilter是我自行實現的,StrutsPrepareAndExecuteFilter是Struts2實現的,這個實現是用於Struts2啟動和初始化的,下面會講到:
4、SSH框架資料流跟蹤
這裡以人物庫管理->新建人物中的上傳人物圖片功能為例,梳理整個框架的流程,功能如下圖:
利用burp攔截訪問請求,如下圖:
上傳圖片請求Action為/CMS/actor/uploadFile.action?channelId=
實時檢查使用者是否登陸Action為/CMS/permission/logincheckUserLoginAction.action
1、通過上傳圖片請求Action的路徑可知需要尋找名稱空間為actor的struts*.xml檔案
檢視struts_actor.xml檔案如下:
2、將Action通過struts框架和spring中bean關聯起來,Struts2會根據struts.xml中配置的class名字在springframeowrk中找id相同的bean,如果找不到就按照普通的方式例項化Action類
例如:
Struts_actor.xml
<action name="uploadFile" class="uploadFileAction" method="uploadImage" >
<interceptor-ref name="defaultStack" />
<result type="json" name="success">
<param name="root">mapJson</param>
</result>
</action>
applicationContext_actor.xml
<bean name="uploadFileAction" class="com.ctvit.icms.standard.actor.biz.UploadFileAction" scope="prototype">
<property name="issueService" ref="issueService" />
<property name="cacheManager" ref="CacheManager" />
</bean>
則class為 uploadFileAction的Action對應com.ctvit.icms.standard.actor.biz.UploadFileAction。
3、在java檔案中檢視uploadImage方法