引入:javascript
這篇文章咱們來專門探討如何防範來自外部的XSS***。html
實踐:java
其實從http://supercharles888.blog.51cto.com/609344/1339921 文章中能夠看出,主要的***手段無讓***者機器上運行一段JS,這段js中包含一段對於document.cookie的處理,若是這個能拿到正確的值,那麼就能夠用獲取的信息發送到***者的某個指定機器上,從而盜用。因此從這個思路上想解決方法就很容易了,就是經過一段機制,讓植入到***者機器上的惡意的js代碼中拿document.cookie拿不到內容。web
能實現這一點麼,簡單查閱了下文檔,發現了原來有Cookie 有個HttpOnly這麼個標記,若是把它設置爲true的時候,那麼這個cookie只能經過http協議訪問,而沒法經過javascript 腳本,或者applet進行訪問。咱們在想,既然信息的盜用都是一段js腳本去拿到document.cookie的內容,那麼若是設置Cookie爲HttpOnly後,是否解決問題了呢?瀏覽器
爲此,咱們作個實驗,咱們讓Cookie用java代碼生成而不是和上文鏈接中的用某段js生成(這樣作的目的是萬一HttpOnly真起做用了,那麼咱們設置Cookie的這段js代碼就生效了)服務器
代碼很簡單,咱們作了一個Servlet,而後讓用戶訪問這個Servlet的時候,它會建立一個Cookie(如今hard-coded):爲了比較,咱們先作一個不設置HttpOnly的例子:cookie
代碼以下:session
package com.charles.study; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 這個Servlet用於產生一個Cookie * @author charles.wang * */ public class CookieServlet extends HttpServlet{ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { buildResponseWithCookie(response); } /** * hard-code一個Cookie信息,而且寫到客戶端 * @param response * @throws IOException */ private void buildResponseWithCookie(HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); Cookie cookie = new Cookie("charles","1234567890"); cookie.setMaxAge(24*3600); cookie.setPath("/"); response.addCookie(cookie); out.println("Already Written Cookie to Client"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
而後在 web.xml中定義好 servlet-mapping(略去)app
而後當咱們訪問頁面時候,打開Firebug,切換到Cookie標籤:ide
能夠看到,默認狀況下,這個Cookie的HttpOnly屬性是沒有設置值的(下方表格第七欄)
如今,咱們切換到Console標籤頁,而後輸入document.cookie:
紅色部分顯示,這時候咱們是拿獲得cookie的值的,也就是說js徹底能夠獲取cookie的內容。
如今咱們把咱們的代碼變下,在建立cookie的地方,加一行 cookie.setHttpOnly(true);
/** * hard-code一個Cookie信息,而且寫到客戶端 * @param response * @throws IOException */ private void buildResponseWithCookie(HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); Cookie cookie = new Cookie("charles","1234567890"); cookie.setMaxAge(24*3600); cookie.setPath("/"); //如下這行專門用於解決來自外部的XSS***問題 cookie.setHttpOnly(true); response.addCookie(cookie); out.println("Already Written Cookie to Client"); }
其餘不變,而後咱們重複上面實驗,咱們打開這個servlet頁面,打開Firebug,切換到Cookie標籤:
這時候能夠發現第7列HttpOnly屬性被設置了。
如今,咱們切換到Console標籤頁,而後輸入document.cookie:
此次咱們發現,這個Cookie再也不顯示「charles=1234567890"了,取而代之的是,它只顯示""空,這就代表,咱們的HttpOnly屬性起做用了。咱們的惡意js沒法經過document.cookie拿到任何有價值信息。
結論的延伸:
因而,從上面2個實驗對比,咱們發現了HttpOnly屬性是解決來自外部XSS***的關鍵屬性,咱們不知足上面實驗,咱們還能夠進行擴展,由於上述實驗中,咱們是讓response直接添加了一個cookie, 然現實中的例子多數是經過會話HttpSession,而後它的scope上添加了一些機密信息,而且維護在服務器端的。而後客戶端也會有一個id去引用這個對應的session,那麼這個Session是否可使用HttpOnly屬性呢?答案是確定的。
若是你使用的是servlet 3.0+的版本,那麼在對應的web.xml中,能夠自然的經過下面一段代碼來配置HttpOnly屬性:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" 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_3_0.xsd"> <display-name>XSSDemo</display-name> <session-config> <cookie-config> <http-only>true</http-only> </cookie-config> </session-config> ..
這裏,注意咱們的xsd是servlet 3.0的xsd,因此咱們能夠在<session-config>中使用 <cookie-config>子元素,而後用<http-only>爲true來啓用這個HttpOnly特徵。
咱們來作個實驗證實,咱們修改下CookieServlet,從而當咱們訪問這個Servlet時候他會建立一個Session:
public class CookieServlet extends HttpServlet{ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session= request.getSession(); session.setAttribute("charles_session","9876543210"); response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("Session Created"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
而後咱們訪問頁面:
顯然,從第七列看出來,這個剛建立的Session Cookie ,它的HttpOnly被正確的設置了。
總結:
咱們作了幾個實驗,大致上解決了外部XSS***的問題,主要是經過設置HttpOnly屬性,這個屬性可防止js或者applet去操做cookie,並且它不只適用於通常的Cookie,也適用於Session Cookie. 其實它的思想很簡單,既然外部XSS***是你把情報帶出去,那麼我海關就嚴格一條,任何紙條只要經過海關就」燒「掉(我只是打個比方) ,這樣你無論如何,你都不能經過惡意代碼從這個灰燼的紙條中拿到信息了。
實踐上看,對於通常的Cookie,只要在它建立的時候,設置cookie.setHttpOnly(true).
對於Session Cookie,若是你的app容器支持servlet 3.0規範,那麼只要配置 <cookie-config>讓其啓用<http-only>就能夠了,若是你的app容器比較老,那麼你必須經過覆寫SET-COOKIE的 Http響應頭來顯式添加HttpOnly標誌。
//經過覆寫SET-COOKIE的 Http響應頭來顯式的添加HttpOnly String sessionid = request.getSession().getId(); response.setHeader("SET-COOKIE", "JSESSIONID=" + sessionid + "; HttpOnly");
其實,如今主流的瀏覽器都能很好的支持HttpOnly了,***們要***難度又加大了。