《TOMCAT权威指南》摘抄
1.對每條ab請求,可以采用下列步驟得到基準調校的結果:
?1.配置并重啟被測試的Apache httpd和/或Tomcat實例。
2.確信服務器日志沒有啟動錯誤。如果有,請按照前面描述的步驟修正錯誤。
3.在服務器重啟后,運行ab命令請求,讓服務器服務于首次請求。
4.作為基準調校的一部分,再次運行ab命令行。
5.在所有的請求都完成時,確信ab報告了零錯誤及non-2xx零響應。
6.在ab請求之間等待幾秒鐘,從而服務器能返回空閑狀態。
7.注意在ab統計信息中每秒的請求數。
8.如果每秒的請求數發生了明顯變化,請返回到第4步;否則,每秒的反復請求數就是基準調校的結果。如果該數字經過ab的10次反復請求仍繼續發生明顯變化,則放棄,記錄最后的每秒請求數,作為基準調校的結果。
2.預編譯的jsps.xml Ant構建文件
<project name="pre-compile-jsps" default="compile-jsp-servlets"><!-- 私有屬性 --><property name="webapp.dir" value="${basedir}/webapp-dir" /><property name="tomcat.home" value="/opt/tomcat"/><property name="jspc.pkg.prefix" value="com.mycompany"/><property name="jspc.dir.prefix" value="com/mycompany"/><!-- 編譯屬性 --><property name="debug" value="on" /><property name="debuglevel" value="lines,vars,source" /><property name="deprecation" value="on" /><property name="encoding" value="ISO-8859-1" /><property name="optimize" value="off" /><property name="build.compiler" value="modern"/><property name="source.version" value="1.5" /><!-- 初始化路徑 --><path id="jspc.classpath"><fileset dir="${tomcat.home}/bin"><include name="*.jar"/></fileset><fileset dir="${tomcat.home}/server/lib"><include name="*.jar"/></fileset><fileset dir="${tomcat.home}/common/i18n"><include name="*.jar"/></fileset><fileset dir="${tomcat.home}/common/lib"><include name="*.jar"/></fileset><fileset dir="${webapp.dir}/WEB-INF"><include name="lib/*.jar"/></fileset><pathelement location="${webapp.dir}/WEB-INF/classes"/><pathelement location="${ant.home}/lib/ant.jar"/><pathelement location="${java.home}/../lib/tools.jar"/></path><property name="jspc.classpath" refid="jspc.classpath"/><!-- ========================================== --><!-- 從JSP文件產生JAVA源碼和web.xml文件 --><!-- ========================================== --><target name="generate-jsp-java-src"><mkdir dir="${webapp.dir}/WEB-INF/jspc-src/${jspc.dir.prefix}"/><taskdef classname="org.apache.jasper.JspC" name="jasper2"><classpath><path refid="jspc.classpath"/></classpath></taskdef><touch file="${webapp.dir}/WEB-INF/jspc-web.xml"/><jasper2 uriroot="${webapp.dir}"package="${jspc.pkg.prefix}"webXmlFragment="${webapp.dir}/WEB-INF/jspc-web.xml"outputDir="${webapp.dir}/WEB-INF/jspc-src/${jspc.dir.prefix}"verbose="1" /></target><!-- ========================================= --><!-- 編譯JSP servlet并由此產生Java類文件 --><!-- 由JspC任務產生的源碼 --><!-- ========================================= --><target name="compile-jsp-servlets" depends="generate-jsp-java-src"><mkdir dir="${webapp.dir}/WEB-INF/classes"/><javac srcdir="${webapp.dir}/WEB-INF/jspc-src"destdir="${webapp.dir}/WEB-INF/classes"includes="**/*.java"debug="${debug}"debuglevel="${debuglevel}"deprecation="${deprecation}"encoding="${encoding}"optimize="${optimize}"source="${source.version}"><classpath><path refid="jspc.classpath"/></classpath></javac></target><!-- ========================================= --><!-- 清除所有預編譯的JSP源碼、類和jspc-web.xml --><!-- ========================================= --><target name="clean"><delete dir="${webapp.dir}/WEB-INF/jspc-src"/><delete dir="${webapp.dir}/WEB-INF/classes/${jspc.dir.prefix}"/><delete file="${webapp.dir}/WEB-INF/jspc-web.xml"/></target></project>3.記住雖然Tomcat是開源的,但它也是一個非常復雜的應用程序,因此在開始修改源碼之前,一定要小心謹慎。如果決定要投入Tomcat源碼開發,請使用Tomcat的郵件列表以分享您的想法,并與社區互動。
4.使用APR連接器,而不使用JIO或NIO的連接器,原因有以下幾點:
1.HTTPS使用APR連接器可能會更快,因為APR連接器是叫做OpenSSL庫文件的本地代碼。而JIO和NIO連接器是純粹的Java代碼,并使用了純粹的Java TLS/SSL編碼,大家都知道,比OpenSSL要慢一些。但是,如果沒有使用HTTPS,則不用關心這一點。
2.對于某些代碼場合(主要是AJP),APR可能會更高效。對這種配置,具有最大吞吐量是比較重要的。
3.由于使用的sendfile(2)系統呼叫,所以APR被設計為處理大型靜態文本文件(如提供媒體文件)時更高效。
4.任何連接器實現的所有底層網絡編碼都是固有的(native)(如JVM是在C/C++中編寫的),因此,無論您是否更喜歡APR,取決于您是喜歡來自ASF還是JVM提供商提供的本地網絡編碼(native network code)。
5.APR一個被廣泛接受的用于Web服務器的I/O實現,用C編程語言編寫(供Apache httpd使用),而且工作正常。
6.在MS-Windows上,NIO連接器并沒有真正起作用,因為NIO似乎在Windows上無法正常發揮作用,至少在使用Sun的Java VM時是這樣。在其他操作系統上,這不成為問題。
7.APR使用了便攜的、安全隨機數產生器,從而Tomcat會話ID在Windows上默認是安全的。
8.APR還有一些其他功能是非常有用的,而核心Java平臺并沒有提供這些功能。關鍵是APR是不同于Java的實現,而且包含一組不同的功能。這些新功能可能會放在任何新版的APR中,而且可以修改APR連接器以充分利用這些功能。
5.如果想顯示配置一個Connector以使用APR,則可按如下方式設置協議屬性:
<Connector port="8080"protocol="org.apache.coyote.http11.Http11AprProtocol"disableUploadTimeout="false"maxThreads="150" connectionTimeout="20000"redirectPort="8443" />6.若要讓Apache httpd保護WEB-INF及META-INF目錄,請在httpd.conf中追加下列內容:
<LocationMatch "/WEB-INF/">AllowOverride Nonedeny from all </LocationMatch> <LocationMatch "/META-INF/">AllowOverride Nonedeny from all </LocationMatch>把所有Web應用程中對.htaccess的請求都映射給叫做forbidden.jsp的JSP文件:
<servlet><servlet-name>htaccess</servlet-name><jsp-file>/forbidden.jsp</jsp-file> </servlet><servlet-mapping><servlet-name>htaccess</servlet-name><url-pattern>*.htaccess</url-pattern> </servlet-mapping>7.一個簡單的HttpServlet,它會在文件系統上創建一個文件,并輸出文件成功寫入的消息。
package com.oreilly.tomcat.servlets;import java.io.File; import java.io.FileOutputStream; import java.io.IOTxception; import java.io.PrintWriter;import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse;/*** 該servlet嘗試在Web應用程序的文檔中寫入文檔根目錄*/ public class WriteFileServlet extends GenericServlet {public void service(ServletRequest request, ServletResponse response)throws IOException, ServletException{//嘗試打開一個文件并寫入。String catalinaHome = "/opt/tomcat";File testFile = new File(catalinaHome + "/webapps/ROOT", "test.txt");FileOutputStream fileOutputStream = new FileOutputStream(testFile);fileOutputStream.write(new String("testing...\n").getBytes());fileOutputStream.close();//如果執行到此,表示文件已成功地創建了。PrintWriter out = response.getWriter();out.println("File created successfully!");} }為了便于在ROOT Web應用程序中編譯、安裝及測試,編寫了下面這個servlet:
# mkdir $CATALINA_HOME/webapps/ROOT/WEB-INF/classes
# export CATALINA_HOME=/opt/tomcat
# javac -classpath $CATALINA_HOME/lib/servlet-api.jar -d $CATALINA_HOME/webapps/ROOT/WEB-INF/classes WriteFileServlet.java
然后, 在ROOT Web應用程序的WEB-INF/web.xml部署描述符中加入servlet和servlet-mapping元素:
現在啟用SecurityManager并重新啟動Tomcat.
然后,訪問URL http://localhost:8080/writefile。
8.編寫tc-chroot init腳本,以便使用jbchroot而非chroot的絕對路徑,并給jbchroot傳入一個或多個開關參數來更改用戶組和/或組:
#!/bin/sh # # chrooted Apache Tomcat servlet容器的linux init腳本。 # # chkconfig: 2345 96 14 # 說明: Apache Tomcat servlet容器 # 進程名: tc-chroot # config: /opt/chroot/tomcat/conf/tomcat-env.sh #APP_ENV="/opt/tomcat/conf/tomcat-env.sh"# 如果存在,則尋找app config文件的源文件。 [ -r "$APP_ENV" ] && . "${APP_ENV}"# 對應于Tomcat 啟動/停止 腳本的路徑。 TOMCAT_SCRIPT=$CATALINA_HOME/bin/catalina.sh# 程序名 PROG="$0"# 解決 links - $0 可以是一個軟鏈接。 while [ -h "$PROG" ]; dols=`ls -ld "$PROG"`link=`expr "$ls" : `.*-> \(.*\)$'`if expr "$link" : '.*/.*' > /dev/null; thenPROG="$link"elsePROG=`dirname "$PROG"`/"$link"fi donePROG="`basename $PROG`" case "$1" instart)echo -n "Starting $PROG: "# Mount /proc.mkdir -p /opt/chroot/procmount -t proc proc /opt/chroot/proc &>/dev/null/usr/local/bin/jbchroot -U tomcat -- /opt/chroot \/bin/bash -c "set -a; . $APP_ENV; \$TOMCAT_SCRIPT start" &>/dev/nulllet RETVAL=$?if [ $RETVAL -eq 0 ]; thenecho "[ OK ]"elseecho "[ FAILED ]"fi;;stop)echo -n "Stopping $PROG: "/usr/local/bin/jbchroot -U tomcat -- /opt/chroot \/bin/bash -c "set -a; . $APP_ENV; \$TOMCAT_SCRIPT stop" &>/dev/nulllet RETVAL=$?if [ $RETVAL -eq 0 ]; then# Give Tomcat some time to perperly stop all webapps.sleep 3# Unmount /proc.umount /opt/chroot/proc &>/dev/nullecho "[ OK ]"elseecho "[ FAILED ]"fi;;*)echo "Usage: tc-chroot {start|stop}"exit 1 esac9.存在SQL注入的一段代碼:
//已經連接到數據庫了,創建使用的Statement Statement statement = connection.createStatement();//創建用于用戶登陸的包含SQL查詢的常規字符串 // inserting the username and password into the String. String queryString = "select * from USER_TABLE where USERNAME='" + username + "' and PASSWORD='" + password + "';";// 用計劃好的字符串執行該SQL查詢 ResultSet resultSet = statement.executeQuery(queryString);// 從數據庫中返回結果行,表明用戶已登錄。10.BadInputValve屬性
className? ? ? ?此Valve實現的Java類名,必須設為com.oreilly.tomcat.valves.BadInputValve
escapeQuotes? ?在執行請求之前、決定此Valuve是否要轉義請求參數中的任何引號(包括雙引、單引號和反引號)。默認值為false
escapeAngleBrackets? 在執行請求之前,決定此Valves是否要轉移參數中的任何尖括號。默認值為false
escapeJavaScript? 決定此Valve是否要轉義請求參數中任何潛在威脅JavaScript函數與對象的引用。默認值為true
allow? 以逗號分隔的一組常規表達式,使該Valve允許處理一個請求。可以不設定,表示指定none。如果沒有設置allow而設置了一個或多個deny,則不允許處理請求
deny? ?以逗號分隔的一組常規表達式,使該Valve拒絕請求。如果在deny清單中,有一個常規表達式與參數名或值的一部分相匹配,則決絕請求。如果沒有設定deny且沒有設定allow,則表示允許所有請求并過濾其參數。如果沒有設定deny,但設置了一個或多個allow,則只有一個或多個allow模式與參數名或值的一部分匹配時,該Valve才允許處理請求。
11.以下是請求所需并安裝商業服務器X.509認證的簡要步驟:
1.產生服務器端的密鑰對,并存儲在一個密鑰庫中;
2.根據密鑰對產生認證簽名請求(sertificate signing request, CSR).
3.要想從誰那里購買商業服務器授權證書(CA),就把CSR發送給他。
4.接收返回的CA認證及新簽名的認證;
5.把該CA認證導入到所安裝的Java的cacerts密鑰庫中。這將允許JVM把您的CA認證辨認為證書授權認證。
6.把簽名服務器證書導入到已存儲服務器密鑰對的相同密鑰庫中。
12.$CATALINA_HOME/conf目錄中的主要配置文件:
server.xml? ? ?Tomcat主配置文件
web.xml? ?servlet與其他適用于整個Web應用程序設置的配置文件,必須符合servlet規范的標準格式。
tomcat-users.xml? ?Tomcat的UserDatabaseRealm用于認證的默認角色、用戶以及密碼清單。
catalina.policy? Tomcat的Java安全防護策略文件。
context.xml? 默認的context設置,應用于安裝了Tomcat的所有主機的所有部署內容。
13.filter過濾器允許您用幾個程序建立管道。過濾器可以在待定的URL模式交給目標的servlet之前,以及在執行servlet之后,用一段程序來處理這些URL模式。Filter元素有幾個子元素:
| 元素 | 必要性 | 含義 |
| icon | 可選的 | 用于在GUI工具中顯示 |
| filter-name | 必要的 | 用于filter-mapping的名稱 |
| display-name | 可選的 | 用于在GUI工具中顯示 |
| description | 可選的 | 用于在GUI工具中顯示 |
| filter-class | 必要的 | 過濾器的完整Java類名 |
| init-param | 0或更多 | 此特定過濾器的初始化參數 |
14.servlet元素可以讓您給servlet或JSP分配名稱,以便用于servlet-mapping及指向一個servlet的其他元素中。
子元素:
| 子元素名 | 可允許的質量 | 含義 |
| icon | 可選擇 | 顯示圖形的圖標 |
| servlet-name | 必要 | 名稱,如前所述 |
| display-name | 可選擇 | 表達GUI工具中的顯示名稱與描述信息 |
| description | 可選擇 | servlet的描述 |
| servlet-class后jsp-file | 必要 | 一個被命名與描述的servlet或JSP名稱 |
| init-param | 0個或多個 | servlet專屬的初始化參數 |
| load-on-startup | 可選擇 | 當啟動Tomcat時加載servlet的順序 |
| run-as | 可選擇 | 用來執行此servlet的用戶角色名稱 |
| security-role-ref | 0個或多個 | 安全防護的角色(相關細節請參閱第2章) |
在Tomcat中,用來編譯及執行所有Jsp的JspServlet,其url-pattern元素為:
<servlet-mapping><servlet-name>jsp</servlet-name><url-pattern>*.jsp</url-pattern> </servlet-mapping>15.捕捉給定Context(已改變URI)的任何請求,并將這些請求映射到JSP(以輸出更新后的URI):
<web-app><servlet><servlet-name>Redirector</servlet-name><jsp-file>/redirector.jsp</jsp-file><load-on-startup>1</load-on-startup></servlet><!-- 將所有的請求都映射到Redirector servlet --><servlet-mapping><servlet-name>Redirector</servlet-name><url-pattern>/*</url-pattern></servlet-mapping> </web-app>16.session-config
<session-config><session-timeout>30</session-timeout> </session-config>17.如果想將符合*.foo的文件名映射到MIME類型的application/x-ian-test-file,則可以通過追加下列mime-mapping元素:
<mime-mapping><extension>foo</extension><mime-type>application/x-ian-test-file</mime-type> </mime-mapping>18.jdchroot.c源碼:
/** jdchroot.c* Linux 和 Solaris 上OpenBSD的chroot命令,由Jason Brittain提供 */ #ifndef lint static const char copyright[] ="@(#) Copyright (c) 1988, 1993\n\The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */#ifndef lint #if 0 static const char sccsid[] = "@(#)chroot.c 8.1(Berkeley) 6/9/93"; #else static const char rcsid[] = "$OpenBSD: chroot.c,v 1.7 2002/10/29 23:12:06 millert Exp $"; #endif #endif /* not lint */#include <ctype.h> #include <errno.h> #include <grp.h> #include <limits.h> #include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>int main(int, char **); void usage(char *); static char *getToken(char **, const char *); int main(int argc, char **argv) {struct group *gp;struct passwd *pw;const char *shell;char *fulluser, *user, *group, *grouplist, *endp, *p;gid_t gid, gidlist[NGROUPS_MAX];uid_t uid;int ch, gids;unsigned long ul;char *myname;myname = argv[0];gid = 0;uid = 0;gids = 0;user = fulluser = group = grouplist = NULL;while ((ch = getopt(argc, argv, "G:g:U:u:")) != -1) {switch(ch) {case 'U':fulluser = optarg;if (*fulluser == '\0')usage(myname);break;case 'u':user = optarg;if (*user == '\0')usage(myname);break;case 'g':group = optarg;if (*group == '\0')usage(myname);break;case 'G':grouplist = optarg;if (*grouplist == '\0')usage(myname);break;case '?':default:usage(myname);}}argc -= optind;argv += optind;if (argc < 1) usage(myname);if (fulluser && (user || group || grouplist)) {fprintf(stderr, "%s: The -U option may not be specified with any other option\n",myname);exit(-1);}if (group != NULL) {if ((gp = getgrnam(group)) != NULL)gid = gp->gr_gid;else if (isdigit((unsigned char)*group)) {errno = 0;ul = strtoul(group, &endp, 10);if (*endp != '\0' || (ul == ULONG_MAX && errno == ERANGE)) {fprintf(stderr, "%s: Invalid group ID `$s'\n", myname, group);exit(-1);}gid = (gid_t)ul;} else {fprintf(stderr, "%s: No such group `%s'\n", myname, group);exit(-1);}if (grouplist != NULL) gidlist[gids++] = gid;if (setgid(gid) != 0) {fprintf(stderr, "%s: setgid", myname);exit(-1);}}while ((p = getToken(&grouplist, ",")) != NULL && gids < NGROUPS_MAX) {if (*p == '\0')continue;if ((gp = getgrnam(p)) != NULL) gidlist[gids] = gp->gr_gid;else if (isdigit((unsigned char)*p)) {errno = 0;ul = strtoul(p, &endp, 10);if (*endp != '\0' || (ul == ULONG_MAX && errno == ERANGE)) {fprintf(stderr, "%s: INvalid group ID `%s'\n", myname, p);exit(-1);}gidlist[gids] = (gid_t)ul;}else {fprintf(stderr, "%s: No such group `%s'\n", myname, p);exit(-1);}/** 如果指定,則忽視主群組,筆者在上面已經追加了一個主群組.*/if (group == NULL || gidlist[gids] != gid)gids++;}if (p != NULL && gids == NGROUPS_MAX) {fprintf(stderr, "%s: Too many supplementary groups provided\n", myname);exit(-1);}if (gids && setgroups(gids, gidlist) != 0){fprintf(stderr, "%s: setgroups", myname);exit(-1);}if (user != NULL) {if ((pw = getpwnam(user)) != NULL)uid = pw->pw_uid;else if (isdigit((unsigned char)*user)) {errno = 0;ul = strtoul(user, &endp, 10);if (*endp != '\0' || (ul = ULONG_MAX && errno == ERANGE)) {fprintf(stderr, "%s: Invalid user ID `%s'\n", myname, user);exit(-1);}uid = (uid_t)ul;}else {fprintf(stderr, "%s: No such user `%s'\n", myname, user);exit(-1);}}if (fulluser != NULL) {if ((pw = getpwnam(fulluser)) == NULL) {fprintf(stderr, "%s: No such user `%s'\n", myname, fulluser);exit(-1);}uid = pw->pw_uid;gid = pw->pw_gid;if (setgid(gid) != 0) {fprintf(stderr, "%s: setgid\n", myname);exit(-1);}if (initgroups(fulluser, gid) == -1) {fprintf(stderr, "%s: initgroups\n", myname);exit(-1);}}if (chroot(argv[0]) != 0 || chdir("/") != 0) {fprintf(stderr, "%s: %s\n", myname, argv[0]);exit(-1);}if ((user || fulluser) && setuid(uid) != 0) {fprintf(stderr, "%s: setuid\n", myname);exit(-1);}if (argv[1]) {execvp(argv[1], &argv[1]);fprintf(stderr, "%s: %s\n", myname, argv[1]);exit(-1);}if ((shell = getenv("SHELL")) == NULL) shell = "/bin/sh";execlp(shell, shell, "-i", (char *)NULL);fprintf(stderr, "%s, %s\n", myname, shell);/* 沒有走樣 */ }void usage(char *myname) {(void)fprintf(stderr, "usage: %s [-g group] [-G group,group,...] ""[-u user] [-U user] newroot [command]\n", myname);exit(1); }/* 這是Solaris上丟失的strsep的替代品. */ static char *getToken(char **str, const char *delims) {char *token;if (*str == NULL) {/* No more tokens */return NULL;}token = *str;while (**str != '\0') {if (strchr(delims, **str) != NULL) {**str = '\0';(*str)++;return token;}(*str)++;}/* There is no other token */*str = NULL;return token; }19.BadInputValve.java
package com.oreilly.tomcat.valve;import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.regex.Matcher; import java.util.regex.Pattern;import javax.servlet.ServletException; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.util.ParameterMap; import org.apache.catalina.valves.RequestFilterValve; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory;/*** 過濾惡意用戶從HTT請求產生的輸入,* 避免遭受包括Cross Site Scripting(XSS)、SQL注入、* 和HTML注入漏洞及其他黑客攻擊。 */ public class BadInputValve extends RequestFilterValve {// -----------------------------------------靜態變量/*** 記錄日志的Log實例。*/private static Log log = LogFactory.getLog(BadInputValve.class);/*** 關于這一實現的描述信息*/protected static String info ="com.oreilly.tomcat.valve.BadInputValve/2.0";/*** 空字符串數組,重用為toArray()的類型指示器。*/private static final String[] STRING_ARRAY = new String[0];// -----------------------------------------實例變量/*** 該標志判斷轉義引號(escape quotes)是否為請求的一部分。*/protected boolean escapeQuotes = false;/*** 該標志判斷轉義尖括號(escape angle brackets)是否為請求的一部分。*/protected boolean escapeAngleBrackets = false;/*** 該標志判斷轉義JavaScript (escape JavaScript)函數和對象名是否為請求的一部分.*/protected boolean escapeJavaScript = false;/*** 替代映射 (映射、替代的常規表達式)。* 用于替代單引號(') 和雙引號(")的轉義等同物。* 使其無法用于惡意目的。*/protected HashMap<String, String> quotesHashMap =new HashMap<String, String>();/*** 替代映射(映射、替代的常規表達式)。* 用于替代尖括號(<>)的轉義等同物。使其無法用于惡意目的。*/protected HashMap<String, String> angleBracketsHashMap = new HashMap<String, String>();/*** 替代映射( 映射、替代的常規表達式)。* 用于替代存在安全隱患的JavaScript函數調用轉義等同物。* 使其無法用于惡意目的。*/protected HashMap<String, String> javaScriptHashMap = new HashMap<String, String>();/*** 用于過濾參數的常規表達式映射。* 如果找到了檢索的字符串,則關鍵在于檢查的常規表達式字符串,* 及用于修改參數的常規表達式字符串。*/protected HashMap<String, String> parameterEscapes =new HashMap<String, String>();// ------------------------------構造器/*** 構建這個類的新實例,包括默認屬性值。*/public BadInputValve() {super();//輸出regex轉義映射。quotesHashMap.put("\"", """);quotesHashMap.put("\'", "'");quotesHashMap.put("`", "`");angleBracketsHashMap.put("<", "<");angleBracketsHashMap.put(">", ">");javaScriptHashMap.put("document(.*)\\.(.*)cookie", "document.cookie");javaScriptHashMap.put("eval(\\s*)\\(", "eval(");javaScriptHashMap.put("setTimeout(\\s*)\\(", "setTimeout$1(");javaScriptHashMap.put("setInterval(\\s*)\\(", "setInterval$1(");javaScriptHashMap.put("execScript(\\s*)\\(", "execScript$1(");javaScriptHashMap.put("(?i)javascript(?-i):", "javascript:");log.info("BadInputValve instantiated.");}// --------------------------------------------屬性/*** 在執行請求之前,獲取一個標志,決定該門限(Valve)是否將轉義作為請求一部分的引號(雙引號和單引號)。*/public boolean getEscapeQuotes() {return escapeQuotes;}/*** 在執行請求之前,獲取一個標志,決定該門限(Valve)是否將轉義作為請求一部分的引號(雙引號和單引號)。*//** @param escapeQuotes*/public void setEscapeQuotes(boolean escapeQuotes) {this.escapeQuotes = escapeQuotes;if (escapeQuotes) {//轉義所有引號。parameterEscapes.putAll(quotesHashMap);}}/*** 在執行請求之前,獲取一個標志,決定該門限(Valve)是否將轉義作為請求一部分的尖括號(<>)。*/public boolean getEscapeAngleBrackets() {return escapeAngleBrackets;}/***在執行請求之前,獲取一個標志,決定該門限(Valve)是否將轉義作為請求一部分的尖括號(<>)*/public boolean getEscapeAngleBrackets() {return escapeAngleBrackets;}/*** 在執行請求之前,獲取一個標志,決定該門限(Valve)是否將轉義作為請求一部分的尖括號(<>)。* @param escapeAngleBrackets*/public void setEscapeAngleBrackets(boolean escapeAngleBrackets) {this.escapeAngleBrackets = escapeAngleBrackets;if (escapeAngleBrackets) {// 轉義所有尖括號.parameterEscapes.putAll(angleBracketsHashMap);}}/*** 在執行請求之前,獲取一個標志,決定該門限(Valve)是否將轉義作為請求一部分*的對JavaScript函數的潛在危險引用。*/public boolean getEscapeJavaScript() {return escapeJavaScript;}/*** 在執行請求之前,獲取一個標志,決定該門限(Valve)是否將轉義作為請求* 一部分的對JavaScript函數和對象的潛在危險引用。** @param escapeJavaScript*/public void setEscapeJavaScript(boolean escapeJavaScript) {this.escapeJavaScript = escapeJavaScript;if (escapeJavaScript) {// Escape potentially dangerous JavaScript method calls.parameterEscapes.putAll(javaScriptHashMap);}}/*** 返回關于該門限(Valve)實現的描述信息。*/public String getInfo() {return info;}// ------------------------------------公共方法/*** 在惡意用戶進入web應用程序之前,消除請求參數。** @param request 要被處理的servlet請求* @param response 要被創建的servlet響應** @excaption IOException 如果發生輸入/輸出錯誤* @exception ServletException 如果發生servlet錯誤*/@Overridepublic void invoke(Request request, Response response) throws IOException, ServletException {//跳過對non-HTTP請求與響應的過濾。if (!(request instanceof HttpServletRequest) ||!(response instanceof HttpServletResponse)) {getNext().invoke(request, response);return;}//基于allow和deny,只讓請求通過。if (processAllowAndDenies(request, response)) {//過濾存在安全隱患的JavasScript代碼,//從而在Tomcat開始執行請求之前,//清楚了黑客的請求。filterparameters(request);//執行該請求getNext().invoke(request, response);}}/*** 使用(摘要)RequestFilterValve 的泛函性* 以終止在參數名和參數值中包含禁用字符串模式的請求** * @param request 要被處理的servlet請求* @param response 要被創建的servlet響應** @exception IOException 如果發生輸入/輸出錯誤* @exception ServletException 如果發生servlet錯誤** @return false 如果請求禁止,否則為true。*/public boolean processAllowsAndDenies(Request request, Response response)throws IOException, ServletException {ParameterMap paramMap = (ParameterMap) ((HttpServletRequest) request).getParameterMap();//循環參數清單。Iterator y = paramMap.keySet().iterator();while (y.hasNext()) {String name = (String) y.next();String[] values = ((HttpServletRequest)request).getParameterValues(name);//查看名字中是否包含禁止模式。if (!checkAllowsAndDenies(name, response)) {return false;}// 檢查該模式的參數值。if (values != null) {for (int i=0; i<values.length; i++) {String value = values[i];if (!checkAllowsAndDenies(value, response)) {return false;}}}}// 沒有參數則導致拒絕,將繼續響應請求。return true;}/*** 執行為該Valve配置的過濾,* 映射指定的請求屬性。如果允許處理請求,* 則該方法返回true,否則,* 該方法發送一條Forbidden錯誤響應網頁,并返回false。** <br><br>** 該方法借鑒了RequestFilterValve.process()的大部分精華,* 只有這一方法擁有boolean返回類型而不用調用* getNext().invoke(request, response).** @param property 要過濾的請求屬性。* @param response 要被處理的servlet響應。** @exception IOException 如果發生一個輸入/輸出錯誤* @exception ServletException 如果發生一個error錯誤** @return true 如果仍然允許處理該請求。*/public boolean checkAllowsAndDenies(String property, Response response)throws IOException, ServletException {// 如果既沒有deny也沒有allow,則處理該請求。if (denies.length == 0 && allows.length == 0) {return true;}// 如果有的話,則檢查deny模式。for (int i=0; i<denies.length; i++) {Matcher m = denies[i].matcher(property);if (m.find()) {ServletResponse sres = response.getResponse();if (sres instanceof HttpServletResponse) {HttpServletResponse hres = (HttpServletResponse) sres;hres.sendError(HttpServletResponse.SC_FORBIDDEN);return false;}}}//如果有的話,則檢查allow模式for (int i=0; i<allows.length; i++) {Matcher m = allows[i].matcher(property);if (m.find()) {return true;}}// Allow, 如果指定了denies而沒有指定allowsif (denies.length > 0 && allows.length == 0) {return true;}// 否則,拒絕響應請求。ServletResponse sres = response.getResponse();if (sres instanceof HttpServletResponse) {HttpServletResponse hres = (HttpServletResponse) sres;hres.sendError(HttpServletResponse.SC_FORBIDDEN);}return false;}/*** 對具有安全隱患的內容,如果找到了轉義字符,則過濾所有現存的參數。** @param request 包含該參數的請求。*/public void filterParameters(Request request) {ParameterMap paramMap = (ParameterMap) ((HttpServletRequest) request).getParameterMap();// 解除參數映射上的鎖,從而可以修改該參數。paramMap.setLocked(false);// 循環每個替代模式。Iterator escapesIterator = parameterEscapes.keySet().iterator();while (escapesIterator.hasNext()) {String patternString = (String) escapesIterator.next();Pattern pattern = Pattern.compile(patternString);// 循環參數列表。@SuppressWarnings("unchecked")String[] paramNames = (String[]) paramMap.keySet().toArray(STRING_ARRAY);for (int i=0; i<paramNames.length; i++) {String name = paramNames[i];String[] values = ((HttpServletRequest)request).getParameterValues(name);//查看名字中是否包含該模式。boolean nameMatch;Matcher matcher = pattern.matcher(name);nameMatch = matcher.find();if (nameMatch) {// 參數名與模式匹配,從而可以用修改名字,// 追加參數后作為新名字、移除老名字// 等方法修補之。String newName = matcher.replaceAll((String) parameterEscapes.get(patternString));request.addParameter(newName, values);paramMap.remove(name);log.warn("Parameter name " + name +" matched pattern \"" + patternString +"\". Remote addr: " +((HttpServletRequest) request).getRemoteAddr( ));}// 檢查該模式的參數值。if (values != null) {for (int j=0; j<values.length; j++) {String value = values[j];boolean valueMatch;matcher = pattern.matcher(value);valueMatch = matcher.find( );if (valueMatch) {// 匹配的值,所有修改它,然后賦回數組String newValue;newValue = matcher.replaceAll((String) parameterEscapes.get(patternString));values[j] = newValue;log.warn("Parameter \"" + name +"\"'s value \"" + value +"\" matched pattern \"" +patternString + "\". Remote addr: " +((HttpServletRequest)request).getRemoteAddr( ));}}}}}// 在完成以后,確保鎖住了參數。paramMap.setLocked(true);}/*** 返回該對象的文本表現*/@Overridepublic String toString() {return "BadInputValve";} }?
總結
以上是生活随笔為你收集整理的《TOMCAT权威指南》摘抄的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SprintBoot中JPA的使用
- 下一篇: <深入剖析Tomcat>摘抄