package org.owasp.webgoat.lessons; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.security.MessageDigest; import javax.servlet.http.HttpServletResponse; import org.apache.ecs.Element; import org.apache.ecs.ElementContainer; import org.apache.ecs.StringElement; import org.apache.ecs.html.A; import org.apache.ecs.html.Form; import org.apache.ecs.html.IMG; import org.apache.ecs.html.Input; import org.apache.ecs.html.TD; import org.apache.ecs.html.TR; import org.apache.ecs.html.Table; import org.owasp.webgoat.session.WebSession; import sun.misc.BASE64Encoder; /*************************************************************************************************** * * * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ * * Copyright (c) 2002 - 2007 Bruce Mayhew * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Getting Source ============== * * Source for this application is maintained at code.google.com, a repository for free software * projects. * * For details, please see http://code.google.com/p/webgoat/ */ public class HttpOnly extends LessonAdapter { public final static A ASPECT_LOGO = new A().setHref("http://www.aspectsecurity.com") .addElement( new IMG("images/logos/aspect.jpg").setAlt("Aspect Security").setBorder(0).setHspace(0) .setVspace(0)); private final static Integer DEFAULT_RANKING = new Integer(125); private final static String UNIQUE2U = "unique2u"; private final static String HTTPONLY = "httponly"; private final static String ACTION = "action"; private final static String READ = "Read Cookie"; private final static String WRITE = "Write Cookie"; private final static String READ_RESULT = "read_result"; private boolean httpOnly = false; private boolean readSuccess = false; private boolean writeSuccess = false; private String original = "undefined"; /** * Gets the title attribute of the EmailScreen object * * @return The title value */ public String getTitle() { return ("HTTPOnly Test"); } protected Integer getDefaultRanking() { return DEFAULT_RANKING; } /** * Description of the Method * * @param s * Description of the Parameter * @return Description of the Return Value */ protected Element createContent(WebSession s) { ElementContainer ec = new ElementContainer(); String action = null; String http = null; http = s.getRequest().getParameter(HTTPONLY); action = s.getRequest().getParameter(ACTION); if (http != null) { httpOnly = Boolean.parseBoolean(http); } if (httpOnly) { // System.out.println("HttpOnly: Setting HttpOnly for cookie"); setHttpOnly(s); } else { // System.out.println("HttpOnly: Removing HttpOnly for cookie"); removeHttpOnly(s); } if (action != null) { if (action.equals(READ)) { handleReadAction(s); } else if (action.equals(WRITE)) { handleWriteAction(s); } else { // s.setMessage("Invalid Request. Please try again."); } } try { ec.addElement(makeContent(s)); } catch (Exception e) { s.setMessage("Error generating " + this.getClass().getName()); e.printStackTrace(); } return (ec); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ protected Category getDefaultCategory() { return Category.XSS; } /** * Gets the hints attribute of the EmailScreen object * * @return The hints value */ protected List getHints(WebSession s) { List hints = new ArrayList(); hints.add("Read the directions and try out the buttons."); return hints; } private String createCustomCookieValue() { String value = null; byte[] buffer = null; MessageDigest md = null; BASE64Encoder encoder = new BASE64Encoder(); try { md = MessageDigest.getInstance("SHA"); buffer = new Date().toString().getBytes(); md.update(buffer); value = encoder.encode(md.digest()); original = value; } catch (Exception e) { e.printStackTrace(); } return value; } private void setHttpOnly(WebSession s) { String value = createCustomCookieValue(); HttpServletResponse response = s.getResponse(); String cookie = s.getCookie(UNIQUE2U); if (cookie == null || cookie.equals("HACKED")) { response.setHeader("Set-Cookie", UNIQUE2U + "=" + value + "; HttpOnly"); original = value; } else { response.setHeader("Set-Cookie", UNIQUE2U + "=" + cookie + "; HttpOnly"); original = cookie; } } private void removeHttpOnly(WebSession s) { String value = createCustomCookieValue(); HttpServletResponse response = s.getResponse(); String cookie = s.getCookie(UNIQUE2U); if (cookie == null || cookie.equals("HACKED")) { response.setHeader("Set-Cookie", UNIQUE2U + "=" + value + ";"); original = value; } else { response.setHeader("Set-Cookie", UNIQUE2U + "=" + cookie + ";"); original = cookie; } } private ElementContainer makeContent(WebSession s) { ElementContainer ec = new ElementContainer(); Element r = null; Table t = null; TR tr = null; Form f = null; ec.addElement(new StringElement(getJavaScript())); f = new Form(); t = new Table(); t.setWidth(500); tr = new TR(); tr.addElement(new TD(new StringElement("Your browser appears to be: " + getBrowserType(s)))); t.addElement(tr); tr = new TR(); t.addElement(tr); tr = new TR(); tr.addElement(new TD(new StringElement("Do you wish to turn HTTPOnly on?"))); tr.addElement(new TD(new StringElement("Yes"))); if (httpOnly == true) { r = new Input(Input.RADIO, HTTPONLY, "True").addAttribute("Checked", "true"); } else { r = new Input(Input.RADIO, HTTPONLY, "True").addAttribute("onClick", "document.form.submit()"); } tr.addElement(new TD(r)); tr.addElement(new TD(new StringElement("No"))); if (httpOnly == false) { r = new Input(Input.RADIO, HTTPONLY, "False").addAttribute("Checked", "True"); } else { r = new Input(Input.RADIO, HTTPONLY, "False").addAttribute("onClick", "document.form.submit()"); } tr.addElement(new TD(r)); r = new Input(Input.HIDDEN, READ_RESULT, ""); tr.addElement(r); t.addElement(tr); /* * tr.addElement(new TD(new StringElement("Status: " ))); * t.addElement(tr); if(httpOnly == true) { tr.addElement(new TD(new StringElement("
On
"))); } else { tr.addElement(new TD(new StringElement ("
Off
"))); } t.addElement(tr); t.addElement(new TR(new TD(new * StringElement("
")))); */f.addElement(t); t = new Table(); tr = new TR(); r = new Input(Input.SUBMIT, ACTION, READ).addAttribute("onclick", "myAlert();"); tr.addElement(new TD(r)); r = new Input(Input.SUBMIT, ACTION, WRITE).addAttribute("onclick", "modifyAlert();"); tr.addElement(new TD(r)); t.addElement(tr); f.addElement(t); ec.addElement(f); return ec; } private void handleReadAction(WebSession s) { String displayed = s.getRequest().getParameter(READ_RESULT); if (httpOnly == true) { if (displayed.indexOf(UNIQUE2U) != -1) { s.setMessage("FAILURE: Your browser did not enforce the HTTPOnly flag properly for the '" + UNIQUE2U + "' cookie. It allowed direct client side read access to this cookie."); } else { s.setMessage("SUCCESS: Your browser enforced the HTTPOnly flag properly for the '" + UNIQUE2U + "' cookie by preventing direct client side read access to this cookie."); if (writeSuccess) { if (!this.isCompleted(s)) { makeSuccess(s); readSuccess = false; writeSuccess = false; } } else { if (!this.isCompleted(s)) { s.setMessage("Now try to see if your browser protects write access to this cookie."); readSuccess = true; } } } } else if (displayed.indexOf(UNIQUE2U) != -1) { s.setMessage("Since HTTPOnly was not enabled, the '" + UNIQUE2U + "' cookie was displayed in the alert dialog."); } else { s.setMessage("Since HTTPOnly was not enabled, the '" + UNIQUE2U + "' cookie should have been displayed in the alert dialog, but was not for some reason. " + "(This shouldn't happen)"); } } private void handleWriteAction(WebSession s) { String hacked = s.getCookie(UNIQUE2U); if (httpOnly == true) { if (!original.equals(hacked)) { s .setMessage("FAILURE: Your browser did not enforce the write protection property of the HTTPOnly flag for the '" + UNIQUE2U + "' cookie."); s.setMessage("The " + UNIQUE2U + " cookie was successfully modified to " + hacked + " on the client side."); } else { s .setMessage("SUCCESS: Your browser enforced the write protection property of the HTTPOnly flag for the '" + UNIQUE2U + "' cookie by preventing client side modification."); if (readSuccess) { if (!this.isCompleted(s)) { makeSuccess(s); readSuccess = false; writeSuccess = false; } } else { if (!this.isCompleted(s)) { s.setMessage("Now try to see if your browser protects read access to this cookie."); writeSuccess = true; } } } } else if (!original.equals(hacked)) { s.setMessage("Since HTTPOnly was not enabled, the browser allowed the '" + UNIQUE2U + "' cookie to be modified on the client side."); } else { s.setMessage("Since HTTPOnly was not enabled, the browser should have allowed the '" + UNIQUE2U + "' cookie to be modified on the client side, but it was not for some reason. " + "(This shouldn't happen)"); } } private String getJavaScript() { StringBuffer buffer = new StringBuffer(); buffer.append("\n"); return buffer.toString(); } private String getBrowserType(WebSession s) { int offset = -1; String result = "unknown"; String browser = s.getHeader("user-agent").toLowerCase(); if (browser != null) { if (browser.indexOf("firefox") != -1) { browser = browser.substring(browser.indexOf("firefox")); offset = getOffset(browser); result = browser.substring(0, offset); } else if (browser.indexOf("msie 6") != -1) { result = "Internet Explorer 6"; } else if (browser.indexOf("msie 7") != -1) { result = "Internet Explorer 7"; } else if (browser.indexOf("msie") != -1) { result = "Internet Explorer"; } else if (browser.indexOf("opera") != -1) { result = "Opera"; } else if (browser.indexOf("safari") != -1) { result = "Safari"; } else if (browser.indexOf("netscape") != -1) { browser = browser.substring(browser.indexOf("netscape")); offset = getOffset(browser); result = browser.substring(0, offset); } else if (browser.indexOf("konqueror") != -1) { result = "Konqueror"; } else if (browser.indexOf("mozilla") != -1) { result = "Mozilla"; } } return result; } private int getOffset(String s) { int result = s.length(); for (int i = 0; i < s.length(); i++) { if (s.charAt(i) < 33 || s.charAt(i) > 126) { result = i; break; } } return result; } public Element getCredits() { return super.getCustomCredits("", ASPECT_LOGO); } }