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 126) { result = i; break; } } return result; } public Element getCredits() { return super.getCustomCredits("", ASPECT_LOGO); } }