引入: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了,***们要***难度又加大了。