1 會話標識未更新
1.1 原因
在用戶進入登錄頁面,但還未登錄時,就已經產生了一個session,用戶輸入信息,登錄以后,session的id不會改變,也就是說還是以前的那個session(事實上session也確實不會改變,因為沒有建立新session,原來的session也沒有被銷毀)。
很多人只是讓會話invalidate沒有用(request.getSession().invalidate();),是因為invalidate方法不是真正的將session銷毀,只是將session中的內容清空,所以當invalidate以后再新建session,新建的session其實不是新的,是將之前的session重新啟用了。於是session的id不變就不奇怪了。只有cookie失效掉,才能換成新的session id
1.2 解決
在登錄頁面上加上一段代碼:
request.getSession().invalidate() ; //清空session if (request.getCookies()!=null) { Cookie cookie = request.getCookies()[0]; // 獲取cookie cookie.setMaxAge(0); // 讓cookie過期 }
注:會話失效后,請不要在代碼前面使用SESSION保存數據。
2 SQL注入
2.1 原因
1. 沒有正確過濾轉義字符
在用戶的輸入沒有為轉義字符過濾時,就會發生這種形式的注入式攻擊,它會被傳遞給一個SQL語句。這樣就會導致應用程序的終端用戶對數據庫上的語句實施操縱。比方說,下面的這行代碼就會演示這種漏洞:
statement := "SELECT * FROM users WHERE name = '" + userName + "'; "
將用戶名變量(即username)設置為:a' or 't'='t,此時原始語句發生了變化.
2. 用戶輸入錯誤的數據類型
如果一個用戶提供的字段並非一個強類型,或者沒有實施類型強制,就會發生這種形式的攻擊。當在一個SQL語句中使用一個數字字段時,如果程序員沒有檢查用戶輸入的合法性(是否為數字型)就會發生這種攻擊。例如:
statement := "SELECT * FROM data WHERE id = " + a_variable + "; "
從這個語句可以看出,作者希望a_variable是一個與“id”字段有關的數字。不過,如果終端用戶選擇一個字符串,就繞過了對轉義字符的需要。例如,將a_variable設置為:1; DROP TABLE users,它會將“users”表從數據庫中刪除,SQL語句變成:
SELECT * FROM DATA WHERE id = 1; DROP TABLE users;
3. 數據庫服務器中的漏洞
有時,數據庫服務器軟件中也存在着漏洞,如MYSQL服務器中mysql_real_escape_string()函數漏洞。這種漏洞允許一個攻擊者根據錯誤的統一字符編碼執行一次成功的SQL注入式攻擊。
4. 盲目SQL注入式攻擊
當一個Web應用程序易於遭受攻擊而其結果對攻擊者卻不見時,就會發生所謂的盲目SQL注入式攻擊。有漏洞的網頁可能並不會顯示數據,而是根據注入到合法語句中的邏輯語句的結果顯示不同的內容。這種攻擊相當耗時,因為必須為每一個獲得的字節而精心構造一個新的語句。但是一旦漏洞的位置和目標信息的位置被確立以后,一種稱為Absinthe的工具就可以使這種攻擊自動化。
5. 條件響應
注意,有一種SQL注入迫使數據庫在一個普通的應用程序屏幕上計算一個邏輯語句的值:
SELECT booktitle FROM booklist WHERE bookId = 'OOk14cd' AND 1=1
這會導致一個標准的面面,而語句
SELECT booktitle FROM booklist WHERE bookId = 'OOk14cd' AND 1=2
在頁面易於受到SQL注入式攻擊時,它有可能給出一個不同的結果。如此這般的一次注入將會證明盲目的SQL注入是可能的,它會使攻擊者根據另外一個表中的某字段內容設計可以評判真偽的語句。
6. 條件性差錯
如果WHERE語句為真,這種類型的盲目SQL注入會迫使數據庫評判一個引起錯誤的語句,從而導致一個SQL錯誤。
例如:
SELECT 1/0 FROM users WHERE username='Ralph'
顯然,如果用戶Ralph存在的話,被零除將導致錯誤。
7. 時間延誤
時間延誤是一種盲目的SQL注入,根據所注入的邏輯,它可以導致SQL引擎執行一個長隊列或者是一個時間延誤語句。攻擊者可以衡量頁面加載的時間,從而決定所注入的語句是否為真。
2.2 解決
1. 用預編譯處理語言
要防御SQL注入,用戶的輸入就絕對不能直接被嵌入到SQL語句中。恰恰相反,用戶的輸入必須進行過濾,或者使用參數化的語句。參數化的語句使用參數而不是將用戶輸入嵌入到語句中。在多數情況中,SQL語句就得以修正。然后,用戶輸入就被限於一個參數。下面是一個使用Java和JDBC API例子:
PreparedStatement prep = conn.prepareStatement("SELECT * FROM USERS WHERE PASSWORD=?"); prep.setString(1, pwd);
總體上講,有兩種方法可以保證應用程序不易受到SQL注入的攻擊,一是使用代碼復查,二是強迫使用參數化語句的。強迫使用參數化的語句意味着嵌入用戶輸入的SQL語句在運行時將被拒絕。
2. 軌范出錯處理
防范SQL注入,還要避免出現一些詳細的錯誤消息,因為黑客們可以利用這些消息。要使用一種標准的輸入確認機制來驗證所有的輸入數據的長度、類型、語句、企業規則等。
3. 使用專業的漏洞掃描工具
但防御SQL注入攻擊也是不夠的。攻擊者們目前正在自動搜索攻擊目標並實施攻擊。其技術甚至可以輕易地被應用於其它的Web架構中的漏洞。企業應當投資於一些專業的漏洞掃描工具,如大名鼎鼎的Acunetix的Web漏洞掃描程序等。一個完善的漏洞掃描程序不同於網絡掃描程序,它專門查找網站上的SQL注入式漏洞。最新的漏洞掃描程序可以查找最新發現的漏洞。
3 XSS跨站腳本編制
3.1 原因
它指的是惡意攻擊者往Web頁面里插入惡意html代碼,當用戶瀏覽該頁之時,嵌入其中Web里面的html代碼會被執行,從而達到惡意用戶的特殊目的。XSS屬於被動式的攻擊,因為其被動且不好利用,所以許多人常忽略其危害性。
3.2 解決
在防止這類問題時,輸入內容的轉義效果遠比內容過濾要好。
具體實施可以增加一個request的轉碼過濾器。代碼:
package com.apusic.portal.sso; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.*; import java.util.*; /** * Servlet Filter implementation class SqlEscapeFilter */ public class SqlEscapeFilter implements Filter { /** * Default constructor. */ public SqlEscapeFilter() { // TODO Auto-generated constructor stub } /** * @see Filter#destroy() */ public void destroy() { // TODO Auto-generated method stub } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub // place your code here HttpServletRequest hreq = (HttpServletRequest)request; Map map = hreq.getParameterMap(); Iterator itr = map.keySet().iterator(); while( itr.hasNext() ) { String key = itr.next().toString(); String [] values = hreq.getParameterValues(key); if( values != null ) { for( int i = 0; i < values.length; i++ ) { values[i] = cleanXSS(values[i]); } } hreq.setAttribute(key, values); } // pass the request along the filter chain chain.doFilter(request, response); } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { // TODO Auto-generated method stub } private String cleanXSS(String value) { value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;"); value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", ")"); value = value.replaceAll("'", "& #39;"); value = value.replaceAll("eval\\((.*)\\)", ""); value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\""); value = value.replaceAll("script", ""); return value; } }
配置應用中的web.xml
Web.xml:
<filter> <display-name>SqlEscapeFilter</display-name> <filter-name>SqlEscapeFilter</filter-name> <filter-class>com.apusic.portal.sso.SqlEscapeFilter</filter-class> </filter> <filter-mapping> <filter-name>SqlEscapeFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>
4 XSRF跨站請求偽造
4.1 原因
CSRF利用方式比較類似XSS(跨站腳本 Cross Site Scripting) ,不過不同的是CSRF是構造一個提交來讓其他人訪問后,利用站點對這些人的信任來進行一些所期望的操作.
比如:A和B在同一個有XSS漏洞的站點C,B登錄過D站點,並且有這個D站點的Cookies,這時候如果A構造一個CSRF,內容為給 A在D站點的賬戶轉移一些虛擬幣,如果這時候在C站點瀏覽的B用戶打開了A構造的含有CSRF的頁面,這時候B的D站點用戶會因為對B用戶的信任而進行給 A轉賬的操作.
4.2 解決
此類攻擊的情景相對的比較復雜,具體解決可以參考以下5點:
第一:限制驗證cookie的到期時間。這些cookie的合法時間越短,黑客利用你的Web應用程序的機會就越小。不過,這個時間越短,用戶就越不方便。因此,你需要在安全性和方便性之間進行平衡。
第二:執行重要業務之前,要求用戶提交額外的信息。要求用戶在進行重要業務前輸入口令,這可以防止黑客發動CSRF攻擊(只要瀏覽器中沒有包含口令),因為這種重要信息無法預測或輕易獲得。
第三:使用秘密的無法預測的驗證符號。當保存在用戶瀏覽器中的cookie僅由一次會話確認時,CSRF攻擊才會有效。所以在每次HTTP請求(當然攻擊者無法提前知道)中都有附加的特定會話的信息,這樣就可以挫敗CSRF攻擊。不過,如果這種應用程序存在跨站腳本漏洞,黑客就有可能訪問這種驗證符號。
第四:使用定制的HTTP報頭。如果執行交易的所有請求都使用XMLHttpRequest並附加一個定制的HTTP報頭,同時拒絕缺少定制報頭的任何請求,就可以用XMLHttpRequest API來防御CSRF攻擊。由於瀏覽器通常僅准許站點將定制的HTTP報頭發送給相同站點,從而了防止由CSRF攻擊的源站點所發起的交易。
第五:檢查訪問源的報頭。在瀏覽者發送HTTP請求時,它通常會包含源自訪問源報頭的URL。理論上講,你可以使用這些信息來阻止源自其它任何站點(而不是來自Web應用程序自身)的請求。
綜合公司以往平台報出此類漏洞產出的原因,基本上都可以通過以下簡單做法加以解決:
在請求后面加上一次性令牌。如驗證碼,手機短信驗證,或者sessionID等。
5 登錄錯誤消息憑證枚舉(不充分帳戶封鎖)
5.1 原因
當試圖利用不正確的憑證來登錄時,當用戶輸入無效的用戶名和無效的密碼時,應用程序會分別生成不同的錯誤消息。通過利用該行為攻擊者可以通過反復試驗,加暴力破解來發現應用程序的有效用戶名、再繼續嘗試發現相關聯的密碼。
5.2 解決
不論用戶名或密碼出現問題都提示同樣的錯誤,且同時加上登陸失敗次數達到規定次數,則執行帳戶鎖定功能。
6 HTML注釋敏感信息泄露
6.1 原因
頁面源代碼不正確的注釋方式。
6.2 解決
將html中有關密碼之類的敏感注釋去掉或者用<%-- -%>隱式注釋。
7 應用程序錯誤
7.1 原因
未執行驗證,可能輸入參數數據類型不匹配。
7.2 解決
實行嚴格的數據類型驗證。
8 已解密的登錄請求
8.1 原因
AppScan 的推理是“AppScan 識別了不是通過SSL 發送的密碼參數。
8.2 解決
第一:采用基於SSL的HTTPS傳輸協議
第二:對敏感信息加密並繞過掃描(只要不是采用SSL安全認證即使加密了但是AppScan還是會掃描出來)
<input type="text" id="password1" style="width:195px; height:25px; line-height:25px;border: solid 1px #89B4D6;color:#999" value="10086密碼" onfocus="javascript:clearPass();" onkeyup="this.value=this.value.replace(/./g,'*');" onkeypress="javascript:hiddenPass()"/> <input id="password" type="hidden" name="password" class="inputs_dl" value="" /> 將type為password的改為text,然后用JS做一個假的密碼輸入框,AppScan會掃描type為password的控件。 function hiddenPass(){ var pass = document.getElementById("password1"); var j_pass = document.getElementById("password"); if(event.keyCode==13){ check(); } var keycode=event.keyCode; var keychar=String.fromCharCode(keycode); j_pass.value=j_pass.value+keychar; j_pass.value=j_pass.value.substring(0,pass.length); } function clearPass(){ $("#password1").val(""); $("#password").val(""); }
然后傳輸密碼的時候加個密:
password = base64encode(password);
9 啟用了不安全的HTTP方法
9.1 原因
除標准的GET與POST方法外,HTTP請求還使用其他各種方法。許多這類方法主要用於完成不常見與特殊的任務。如果低權限用戶可以訪問這些方法,他們就能夠以此向應用程序實施有效攻擊。以下是一些值得注意的方法:
PUT,向指定的目錄上傳附加文件;
DELETE,刪除指定的資源;
COPY,將指定的資源復制到Destination消息頭指定的位置;
MOVE,將指定的資源移動到Destination消息頭指定的位置;
SEARCH,在一個目錄路徑中搜索資源。
PROPFIND,獲取與指定資源有關的信息,如作者、大小與內容類型。
TRACE,在響應中返回服務器收到的原始請求。可以使用這種方法避開阻止跨站點腳本的防御
9.2 解決
如何禁止DELETE、PUT、OPTIONS、TRACE、HEAD等協議訪問應用程序應用程序呢?
解決方法
第一步:修改應用程序的web.xml文件的協議
1. <?xml version="1.0" encoding="UTF-8"?> 2. <web-app xmlns="http://java.sun.com/xml/ns/j2ee" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" 5. version="2.4">
第二步:在應用程序的web.xml中添加如下的代碼即可
1. <security-constraint> 2. <web-resource-collection> 3. <url-pattern>/*</url-pattern> 4. <http-method>PUT</http-method> 5. <http-method>DELETE</http-method> 6. <http-method>HEAD</http-method> 7. <http-method>OPTIONS</http-method> 8. <http-method>TRACE</http-method> 9. </web-resource-collection> 10. <auth-constraint> 11. </auth-constraint> 12. </security-constraint> 13. <login-config> 14. <auth-method>BASIC</auth-method> 15. </login-config>
10 禁止頁面緩存
10.1 原因
能夠訪問到緩存的脫機數據導致泄密。
10.2 解決
建議在web管理后台程序的過濾器里增加如下代碼:
response.setHeader("Cache-Control", "no-cache"); //只是請求或響應消息不緩存 response.setHeader("Cache-Control", "no-store"); //在請求消息中發送將使得請求和響應消息都不使用緩存 response.setDateHeader("Expires", 0); //緩存距離過期的時間為0毫秒,即緩存立即過期 response.setHeader("Pragma", "no-cache"); //頁面不緩存
11 數據庫錯誤模式
11.1 原因
主要是一些數據連接錯誤信息,通過提交特殊構造的字符,程序會暴露一些數據庫信息,也容易引起SQL注入攻擊。
現有平台發現的例子:
<html><head><title>Apache Tomcat/5.5.28 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 500 - </h1><HR size="1" noshade="noshade"><p><b>type</b> Exception report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The server encountered an internal error () that prevented it from fulfilling this request.</u></p><p><b>exception</b> <pre>javax.servlet.ServletException: org.hibernate.HibernateException: java.sql.SQLException: ORA-12899: value too large for column "QCSMS"."T_SYS_LOGON_LOG"."USER_CODE" (actual: 24, maximum: 20)