All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.owasp.esapi.reference.DefaultHTTPUtilities Maven / Gradle / Ivy

/**
 * OWASP Enterprise Security API (ESAPI)
 *
 * This file is part of the Open Web Application Security Project (OWASP)
 * Enterprise Security API (ESAPI) project. For details, please see
 * http://www.owasp.org/index.php/ESAPI.
 *
 * Copyright (c) 2007 - The OWASP Foundation
 *
 * The ESAPI is published by OWASP under the BSD license. You should read and accept the
 * LICENSE before you use, modify, and/or redistribute this software.
 *
 * @author Jeff Williams Aspect Security
 * @created 2007
 */
package org.owasp.esapi.reference;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.owasp.esapi.ESAPI;
import org.owasp.esapi.HTTPUtilities;
import org.owasp.esapi.Logger;
import org.owasp.esapi.SecurityConfiguration;
import org.owasp.esapi.StringUtilities;
import org.owasp.esapi.User;
import org.owasp.esapi.ValidationErrorList;
import org.owasp.esapi.codecs.Hex;
import org.owasp.esapi.crypto.CipherText;
import org.owasp.esapi.crypto.PlainText;
import org.owasp.esapi.errors.AccessControlException;
import org.owasp.esapi.errors.AuthenticationException;
import org.owasp.esapi.errors.EncodingException;
import org.owasp.esapi.errors.EncryptionException;
import org.owasp.esapi.errors.IntegrityException;
import org.owasp.esapi.errors.IntrusionException;
import org.owasp.esapi.errors.ValidationException;
import org.owasp.esapi.errors.ValidationUploadException;

/**
 * Reference implementation of the HTTPUtilities interface. This implementation
 * uses the Apache Commons FileUploader library, which in turn uses the Apache
 * Commons IO library.
 * 

* To simplify the interface, some methods use the current request and response that * are tracked by ThreadLocal variables in the Authenticator. This means that you * must have called ESAPI.authenticator().setCurrentHTTP(request, response) before * calling these methods. *

* Typically, this is done by calling the Authenticator.login() method, which * calls setCurrentHTTP() automatically. However if you want to use these methods * in another application, you should explicitly call setCurrentHTTP() in your * own code. In either case, you *must* call ESAPI.clearCurrent() to clear threadlocal * variables before the thread is reused. The advantages of having identity everywhere * outweigh the disadvantages of this approach. * * @author Jeff Williams (jeff.williams .at. aspectsecurity.com) Aspect Security * @since June 1, 2007 * @see org.owasp.esapi.HTTPUtilities */ public class DefaultHTTPUtilities implements org.owasp.esapi.HTTPUtilities { private static volatile HTTPUtilities instance = null; // Apache Commons FileUpload property for enabling / disabling Java deserialization via file uploads. // ESAPI will save current value, set it to "false", and then restore value before returning. GitHub issue #417. private static String DISKFILEITEM_SERIALIZABLE = "org.apache.commons.fileupload.disk.DiskFileItem.serializable"; public static HTTPUtilities getInstance() { if ( instance == null ) { synchronized ( DefaultHTTPUtilities.class ) { if ( instance == null ) { instance = new DefaultHTTPUtilities(); } } } return instance; } /** * Defines the ThreadLocalRequest to store the current request for this thread. */ private class ThreadLocalRequest extends InheritableThreadLocal { public HttpServletRequest getRequest() { return super.get(); } public HttpServletRequest initialValue() { return null; } public void setRequest(HttpServletRequest newRequest) { super.set(newRequest); } } /** * Defines the ThreadLocalResponse to store the current response for this thread. */ private class ThreadLocalResponse extends InheritableThreadLocal { public HttpServletResponse getResponse() { return super.get(); } public HttpServletResponse initialValue() { return null; } public void setResponse(HttpServletResponse newResponse) { super.set(newResponse); } } /** The logger. */ private final Logger logger = ESAPI.getLogger("HTTPUtilities"); /** The max bytes. */ static final int maxBytes = ESAPI.securityConfiguration().getAllowedFileUploadSize(); /* * The currentRequest ThreadLocal variable is used to make the currentRequest available to any call in any part of an * application. This enables API's for actions that require the request to be much simpler. For example, the logout() * method in the Authenticator class requires the currentRequest to get the session in order to invalidate it. */ private ThreadLocalRequest currentRequest = new ThreadLocalRequest(); /* * The currentResponse ThreadLocal variable is used to make the currentResponse available to any call in any part of an * application. This enables API's for actions that require the response to be much simpler. For example, the logout() * method in the Authenticator class requires the currentResponse to kill the Session ID cookie. */ private ThreadLocalResponse currentResponse = new ThreadLocalResponse(); /** * No arg constructor. */ public DefaultHTTPUtilities() { } /** * {@inheritDoc} * This implementation uses a custom "set-cookie" header rather than Java's * cookie interface which doesn't allow the use of HttpOnly. Configure the * HttpOnly and Secure settings in ESAPI.properties. */ public void addCookie( Cookie cookie ) { addCookie( getCurrentResponse(), cookie ); } /** * {@inheritDoc} * This implementation uses a custom "set-cookie" header rather than Java's * cookie interface which doesn't allow the use of HttpOnly. Configure the * HttpOnly and Secure settings in ESAPI.properties. */ public void addCookie(HttpServletResponse response, Cookie cookie) { String name = cookie.getName(); String value = cookie.getValue(); int maxAge = cookie.getMaxAge(); String domain = cookie.getDomain(); String path = cookie.getPath(); boolean secure = cookie.getSecure(); // validate the name and value ValidationErrorList errors = new ValidationErrorList(); String cookieName = ESAPI.validator().getValidInput("cookie name", name, "HTTPCookieName", 50, false, errors); String cookieValue = ESAPI.validator().getValidInput("cookie value", value, "HTTPCookieValue", 5000, false, errors); // if there are no errors, then set the cookie either with a header or normally if (errors.size() == 0) { if ( ESAPI.securityConfiguration().getForceHttpOnlyCookies() ) { String header = createCookieHeader(cookieName, cookieValue, maxAge, domain, path, secure); addHeader(response, "Set-Cookie", header); } else { // Issue 23 - If the ESAPI Configuration is set to force secure cookies, force the secure flag on the cookie before setting it cookie.setSecure( secure || ESAPI.securityConfiguration().getForceSecureCookies() ); response.addCookie(cookie); } return; } logger.warning(Logger.SECURITY_FAILURE, "Attempt to add unsafe data to cookie (skip mode). Skipping cookie and continuing."); } /** * {@inheritDoc} */ public String addCSRFToken(String href) { User user = ESAPI.authenticator().getCurrentUser(); if (user.isAnonymous()) { return href; } // if there are already parameters append with &, otherwise append with ? String token = CSRF_TOKEN_NAME + "=" + user.getCSRFToken(); return href.indexOf( '?') != -1 ? href + "&" + token : href + "?" + token; } /** * {@inheritDoc} */ public void addHeader(String name, String value) { addHeader( getCurrentResponse(), name, value ); } /** * {@inheritDoc} */ public void addHeader(HttpServletResponse response, String name, String value) { try { String strippedName = StringUtilities.replaceLinearWhiteSpace(name); String strippedValue = StringUtilities.replaceLinearWhiteSpace(value); String safeName = ESAPI.validator().getValidInput("addHeader", strippedName, "HTTPHeaderName", 20, false); String safeValue = ESAPI.validator().getValidInput("addHeader", strippedValue, "HTTPHeaderValue", 500, false); response.addHeader(safeName, safeValue); } catch (ValidationException e) { logger.warning(Logger.SECURITY_FAILURE, "Attempt to add invalid header denied", e); } } /** * {@inheritDoc} */ public void assertSecureChannel() throws AccessControlException { assertSecureChannel( getCurrentRequest() ); } /** * {@inheritDoc} * * This implementation ignores the built-in isSecure() method * and uses the URL to determine if the request was transmitted over SSL. * This is because SSL may have been terminated somewhere outside the * container. */ public void assertSecureChannel(HttpServletRequest request) throws AccessControlException { if ( request == null ) { throw new AccessControlException( "Insecure request received", "HTTP request was null" ); } StringBuffer sb = request.getRequestURL(); if ( sb == null ) { throw new AccessControlException( "Insecure request received", "HTTP request URL was null" ); } String url = sb.toString(); if ( !url.startsWith( "https" ) ) { throw new AccessControlException( "Insecure request received", "HTTP request did not use SSL" ); } } /** * {@inheritDoc} */ public void assertSecureRequest() throws AccessControlException { assertSecureRequest( getCurrentRequest() ); } /** * {@inheritDoc} */ public void assertSecureRequest(HttpServletRequest request) throws AccessControlException { assertSecureChannel( request ); String receivedMethod = request.getMethod(); String requiredMethod = "POST"; if ( !receivedMethod.equals( requiredMethod ) ) { throw new AccessControlException( "Insecure request received", "Received request using " + receivedMethod + " when only " + requiredMethod + " is allowed" ); } } /** * {@inheritDoc} */ public HttpSession changeSessionIdentifier() throws AuthenticationException { return changeSessionIdentifier( getCurrentRequest() ); } /** * {@inheritDoc} */ public HttpSession changeSessionIdentifier(HttpServletRequest request) throws AuthenticationException { // get the current session HttpSession oldSession = request.getSession(); // make a copy of the session content Map temp = new ConcurrentHashMap(); Enumeration e = oldSession.getAttributeNames(); while (e != null && e.hasMoreElements()) { String name = (String) e.nextElement(); Object value = oldSession.getAttribute(name); temp.put(name, value); } // kill the old session and create a new one oldSession.invalidate(); HttpSession newSession = request.getSession(); User user = ESAPI.authenticator().getCurrentUser(); user.addSession( newSession ); user.removeSession( oldSession ); // copy back the session content for (Map.Entry stringObjectEntry : temp.entrySet()) { newSession.setAttribute(stringObjectEntry.getKey(), stringObjectEntry.getValue()); } return newSession; } /** * {@inheritDoc} */ public void clearCurrent() { currentRequest.set(null); currentResponse.set(null); } private String createCookieHeader(String name, String value, int maxAge, String domain, String path, boolean secure) { // create the special cookie header instead of creating a Java cookie // Set-Cookie:=[; =][; expires=][; // domain=][; path=][; secure][;HttpOnly] String header = name + "=" + value; if (maxAge >= 0) { header += "; Max-Age=" + maxAge; } if (domain != null) { header += "; Domain=" + domain; } if (path != null) { header += "; Path=" + path; } if ( secure || ESAPI.securityConfiguration().getForceSecureCookies() ) { header += "; Secure"; } if ( ESAPI.securityConfiguration().getForceHttpOnlyCookies() ) { header += "; HttpOnly"; } return header; } /** * {@inheritDoc} */ public String decryptHiddenField(String encrypted) { try { return decryptString(encrypted); } catch( EncryptionException e ) { throw new IntrusionException("Invalid request","Tampering detected. Hidden field data did not decrypt properly.", e); } } /** * {@inheritDoc} */ public Map decryptQueryString(String encrypted) throws EncryptionException { String plaintext = decryptString(encrypted); return queryToMap(plaintext); } /** * {@inheritDoc} */ public Map decryptStateFromCookie() throws EncryptionException { return decryptStateFromCookie( getCurrentRequest() ); } /** * {@inheritDoc} * * @param request */ public Map decryptStateFromCookie(HttpServletRequest request) throws EncryptionException { try { String encrypted = getCookie( request, ESAPI_STATE ); if ( encrypted == null ) return new HashMap(); String plaintext = decryptString(encrypted); return queryToMap( plaintext ); } catch( ValidationException e ) { return null; } } /** * {@inheritDoc} */ public String encryptHiddenField(String value) throws EncryptionException { return encryptString(value); } /** * {@inheritDoc} */ public String encryptQueryString(String query) throws EncryptionException { return encryptString(query); } /** * {@inheritDoc} */ public void encryptStateInCookie(HttpServletResponse response, Map cleartext) throws EncryptionException { StringBuilder sb = new StringBuilder(); Iterator i = cleartext.entrySet().iterator(); while ( i.hasNext() ) { try { Map.Entry entry = (Map.Entry)i.next(); // What do these need to be URL encoded? They are encrypted! String name = ESAPI.encoder().encodeForURL( entry.getKey().toString() ); String value = ESAPI.encoder().encodeForURL( entry.getValue().toString() ); sb.append(name).append("=").append(value); if ( i.hasNext() ) sb.append( "&" ); } catch( EncodingException e ) { logger.error(Logger.SECURITY_FAILURE, "Problem encrypting state in cookie - skipping entry", e ); } } String encrypted = encryptString(sb.toString()); if ( encrypted.length() > (MAX_COOKIE_LEN ) ) { logger.error(Logger.SECURITY_FAILURE, "Problem encrypting state in cookie - skipping entry"); throw new EncryptionException("Encryption failure", "Encrypted cookie state of " + encrypted.length() + " longer than allowed " + MAX_COOKIE_LEN ); } Cookie cookie = new Cookie( ESAPI_STATE, encrypted ); addCookie( response, cookie ); } /** * {@inheritDoc} */ public void encryptStateInCookie( Map cleartext ) throws EncryptionException { encryptStateInCookie( getCurrentResponse(), cleartext ); } /** * {@inheritDoc} */ public String getCookie( HttpServletRequest request, String name ) throws ValidationException { Cookie c = getFirstCookie( request, name ); if ( c == null ) return null; String value = c.getValue(); return ESAPI.validator().getValidInput("HTTP cookie value: " + value, value, "HTTPCookieValue", 1000, false); } /** * {@inheritDoc} */ public String getCookie( String name ) throws ValidationException { return getCookie( getCurrentRequest(), name ); } /** * {@inheritDoc} */ public String getCSRFToken() { User user = ESAPI.authenticator().getCurrentUser(); if (user == null) return null; return user.getCSRFToken(); } /** * {@inheritDoc} */ public HttpServletRequest getCurrentRequest() { return currentRequest.getRequest(); } /** * {@inheritDoc} */ public HttpServletResponse getCurrentResponse() { return currentResponse.getResponse(); } /** * {@inheritDoc} */ public List getFileUploads() throws ValidationException { return getFileUploads( getCurrentRequest(), ESAPI.securityConfiguration().getUploadDirectory(), ESAPI.securityConfiguration().getAllowedFileExtensions() ); } /** * {@inheritDoc} */ public List getFileUploads(HttpServletRequest request) throws ValidationException { return getFileUploads(request, ESAPI.securityConfiguration().getUploadDirectory(), ESAPI.securityConfiguration().getAllowedFileExtensions()); } /** * {@inheritDoc} */ public List getFileUploads(HttpServletRequest request, File finalDir ) throws ValidationException { return getFileUploads(request, finalDir, ESAPI.securityConfiguration().getAllowedFileExtensions()); } /** * {@inheritDoc} */ public List getFileUploads(HttpServletRequest request, File finalDir, List allowedExtensions) throws ValidationException { File tempDir = ESAPI.securityConfiguration().getUploadTempDirectory(); if ( !tempDir.exists() ) { if ( !tempDir.mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create temp directory: " + tempDir.getAbsolutePath() ); } if( finalDir != null){ if ( !finalDir.exists() ) { if ( !finalDir.mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create final upload directory: " + finalDir.getAbsolutePath() ); } } else { if ( !ESAPI.securityConfiguration().getUploadDirectory().exists()) { if ( !ESAPI.securityConfiguration().getUploadDirectory().mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create final upload directory: " + ESAPI.securityConfiguration().getUploadDirectory().getAbsolutePath() ); } finalDir = ESAPI.securityConfiguration().getUploadDirectory(); } List newFiles = new ArrayList(); String dfiPrevValue = "false"; // Fail safely in case of Java Security Manager & weird security policy try { dfiPrevValue = System.getProperty(DISKFILEITEM_SERIALIZABLE); System.setProperty(DISKFILEITEM_SERIALIZABLE, "false"); final HttpSession session = request.getSession(false); if (!ServletFileUpload.isMultipartContent(request)) { throw new ValidationUploadException("Upload failed", "Not a multipart request"); } // this factory will store ALL files in the temp directory, // regardless of size DiskFileItemFactory factory = new DiskFileItemFactory(0, tempDir); ServletFileUpload upload = new ServletFileUpload(factory); upload.setSizeMax(maxBytes); // Create a progress listener ProgressListener progressListener = new ProgressListener() { private long megaBytes = -1; private long progress = 0; public void update(long pBytesRead, long pContentLength, int pItems) { if (pItems == 0) return; long mBytes = pBytesRead / 1000000; if (megaBytes == mBytes) return; megaBytes = mBytes; progress = (long) (((double) pBytesRead / (double) pContentLength) * 100); if ( session != null ) { session.setAttribute("progress", Long.toString(progress)); } // logger.logSuccess(Logger.SECURITY, " Item " + pItems + " (" + progress + "% of " + pContentLength + " bytes]"); } }; upload.setProgressListener(progressListener); List items = upload.parseRequest(request); for (FileItem item : items) { if (!item.isFormField() && item.getName() != null && !(item.getName().equals(""))) { String[] fparts = item.getName().split("[\\/\\\\]"); String filename = fparts[fparts.length - 1]; if (!ESAPI.validator().isValidFileName("upload", filename, allowedExtensions, false)) { throw new ValidationUploadException("Upload only simple filenames with the following extensions " + allowedExtensions, "Upload failed isValidFileName check"); } logger.info(Logger.SECURITY_SUCCESS, "File upload requested: " + filename); File f = new File(finalDir, filename); if (f.exists()) { String[] parts = filename.split("\\/."); String extension = ""; if (parts.length > 1) { extension = parts[parts.length - 1]; } String filenm = filename.substring(0, filename.length() - extension.length()); f = File.createTempFile(filenm, "." + extension, finalDir); } item.write(f); newFiles.add(f); // delete temporary file item.delete(); logger.fatal(Logger.SECURITY_SUCCESS, "File successfully uploaded: " + f); if (session != null) { session.setAttribute("progress", Long.toString(0)); } } } } catch (Exception e) { if (e instanceof ValidationUploadException) { throw (ValidationException)e; } throw new ValidationUploadException("Upload failure", "Problem during upload:" + e.getMessage(), e); } finally { if ( dfiPrevValue != null ) { System.setProperty(DISKFILEITEM_SERIALIZABLE, dfiPrevValue); } } return Collections.synchronizedList(newFiles); } /** * Utility to return the first cookie matching the provided name. * @param request * @param name */ private Cookie getFirstCookie(HttpServletRequest request, String name) { Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals(name)) { return cookie; } } } return null; } /** * {@inheritDoc} */ public String getHeader( HttpServletRequest request, String name ) throws ValidationException { String value = request.getHeader(name); return ESAPI.validator().getValidInput("HTTP header value: " + value, value, "HTTPHeaderValue", 150, false); } /** * {@inheritDoc} */ public String getHeader( String name ) throws ValidationException { return getHeader( getCurrentRequest(), name ); } /** * {@inheritDoc} */ public String getParameter( HttpServletRequest request, String name ) throws ValidationException { String value = request.getParameter(name); return ESAPI.validator().getValidInput("HTTP parameter value: " + value, value, "HTTPParameterValue", 2000, true); } /** * {@inheritDoc} */ public String getParameter( String name ) throws ValidationException { return getParameter( getCurrentRequest(), name ); } /** * {@inheritDoc} */ public void killAllCookies() { killAllCookies( getCurrentRequest(), getCurrentResponse() ); } /** * {@inheritDoc} * * @param request * @param response */ public void killAllCookies(HttpServletRequest request, HttpServletResponse response) { Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { killCookie(request, response, cookie.getName()); } } } /** * {@inheritDoc} * * @param request * @param response * @param name */ public void killCookie(HttpServletRequest request, HttpServletResponse response, String name) { String path = "/"; String domain=""; Cookie cookie = getFirstCookie(request, name); if ( cookie != null ) { path = cookie.getPath(); domain = cookie.getDomain(); } Cookie deleter = new Cookie( name, "deleted" ); deleter.setMaxAge( 0 ); if ( domain != null ) deleter.setDomain( domain ); if ( path != null ) deleter.setPath( path ); response.addCookie( deleter ); } /** * {@inheritDoc} */ public void killCookie( String name ) { killCookie( getCurrentRequest(), getCurrentResponse(), name ); } /** * {@inheritDoc} */ public void logHTTPRequest() { logHTTPRequest( getCurrentRequest(), logger, null ); } /** * {@inheritDoc} */ public void logHTTPRequest(HttpServletRequest request, Logger logger) { logHTTPRequest( request, logger, null ); } /** * Formats an HTTP request into a log suitable string. This implementation logs the remote host IP address (or * hostname if available), the request method (GET/POST), the URL, and all the querystring and form parameters. All * the parameters are presented as though they were in the URL even if they were in a form. Any parameters that * match items in the parameterNamesToObfuscate are shown as eight asterisks. * * * @param request */ public void logHTTPRequest(HttpServletRequest request, Logger logger, List parameterNamesToObfuscate) { StringBuilder params = new StringBuilder(); Iterator i = request.getParameterMap().keySet().iterator(); while (i.hasNext()) { String key = (String) i.next(); String[] value = request.getParameterMap().get(key); for (int j = 0; j < value.length; j++) { params.append(key).append("="); if (parameterNamesToObfuscate != null && parameterNamesToObfuscate.contains(key)) { params.append("********"); } else { params.append(value[j]); } if (j < value.length - 1) { params.append("&"); } } if (i.hasNext()) params.append("&"); } Cookie[] cookies = request.getCookies(); if ( cookies != null ) { for (Cookie cooky : cookies) { if (!cooky.getName().equals(ESAPI.securityConfiguration().getHttpSessionIdName())) { params.append("+").append(cooky.getName()).append("=").append(cooky.getValue()); } } } String msg = request.getMethod() + " " + request.getRequestURL() + (params.length() > 0 ? "?" + params : ""); logger.info(Logger.SECURITY_SUCCESS, msg); } private Map queryToMap(String query) { TreeMap map = new TreeMap(); String[] parts = query.split("&"); for (String part : parts) { try { String[] nvpair = part.split("="); String name = ESAPI.encoder().decodeFromURL(nvpair[0]); String value = ESAPI.encoder().decodeFromURL(nvpair[1]); map.put(name, value); } catch (EncodingException e) { // skip the nvpair with the encoding problem - note this is already logged. } } return map; } /** * {@inheritDoc} * * This implementation simply checks to make sure that the forward location starts with "WEB-INF" and * is intended for use in frameworks that forward to JSP files inside the WEB-INF folder. */ public void sendForward(HttpServletRequest request, HttpServletResponse response, String location) throws AccessControlException,ServletException,IOException { if (!location.startsWith("WEB-INF")) { throw new AccessControlException("Forward failed", "Bad forward location: " + location); } RequestDispatcher dispatcher = request.getRequestDispatcher(location); dispatcher.forward( request, response ); } /** * {@inheritDoc} */ public void sendForward( String location ) throws AccessControlException,ServletException,IOException { sendForward( getCurrentRequest(), getCurrentResponse(), location); } /** * {@inheritDoc} * * This implementation checks against the list of safe redirect locations defined in ESAPI.properties. */ public void sendRedirect(HttpServletResponse response, String location) throws AccessControlException, IOException { if (!ESAPI.validator().isValidRedirectLocation("Redirect", location, false)) { logger.fatal(Logger.SECURITY_FAILURE, "Bad redirect location: " + location); throw new AccessControlException("Redirect failed", "Bad redirect location: " + location); } response.sendRedirect(location); } /** * {@inheritDoc} */ public void sendRedirect( String location ) throws AccessControlException,IOException { sendRedirect( getCurrentResponse(), location); } /** * {@inheritDoc} */ public void setContentType() { setContentType( getCurrentResponse() ); } /** * {@inheritDoc} */ public void setContentType(HttpServletResponse response) { response.setContentType((ESAPI.securityConfiguration()).getResponseContentType()); } /** * {@inheritDoc} */ public void setCurrentHTTP(HttpServletRequest request, HttpServletResponse response) { currentRequest.setRequest(request); currentResponse.setResponse(response); } /** * {@inheritDoc} */ public void setHeader(HttpServletResponse response, String name, String value) { try { SecurityConfiguration sc = ESAPI.securityConfiguration(); String strippedName = StringUtilities.replaceLinearWhiteSpace(name); String strippedValue = StringUtilities.replaceLinearWhiteSpace(value); String safeName = ESAPI.validator().getValidInput("setHeader", strippedName, "HTTPHeaderName", sc.getIntProp("HttpUtilities.MaxHeaderNameSize"), false); String safeValue = ESAPI.validator().getValidInput("setHeader", strippedValue, "HTTPHeaderValue", sc.getIntProp("HttpUtilities.MaxHeaderValueSize"), false); response.setHeader(safeName, safeValue); } catch (ValidationException e) { logger.warning(Logger.SECURITY_FAILURE, "Attempt to set invalid header denied", e); } } /** * {@inheritDoc} */ public void setHeader( String name, String value ) { setHeader( getCurrentResponse(), name, value ); } /** * {@inheritDoc} */ public void setNoCacheHeaders() { setNoCacheHeaders( getCurrentResponse() ); } /** * {@inheritDoc} * * @param response */ public void setNoCacheHeaders(HttpServletResponse response) { // HTTP 1.1 response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); // HTTP 1.0 response.setHeader("Pragma","no-cache"); response.setDateHeader("Expires", -1); } /** * {@inheritDoc} * * Save the user's remember me data in an encrypted cookie and send it to the user. * Any old remember me cookie is destroyed first. Setting this cookie will keep the user * logged in until the maxAge passes, the password is changed, or the cookie is deleted. * If the cookie exists for the current user, it will automatically be used by ESAPI to * log the user in, if the data is valid and not expired. * * @param request * @param response */ public String setRememberToken( HttpServletRequest request, HttpServletResponse response, String password, int maxAge, String domain, String path ) { User user = ESAPI.authenticator().getCurrentUser(); try { killCookie(request, response, REMEMBER_TOKEN_COOKIE_NAME ); // seal already contains random data String clearToken = user.getAccountName() + "|" + password; long expiry = ESAPI.encryptor().getRelativeTimeStamp(maxAge * 1000); String cryptToken = ESAPI.encryptor().seal(clearToken, expiry); SecurityConfiguration sg = ESAPI.securityConfiguration(); boolean forceSecureCookies = sg.getBooleanProp("HttpUtilities.ForceSecureCookies"); boolean forceHttpOnly = sg.getBooleanProp("HttpUtilities.ForceHttpOnlyCookies"); // Do NOT URLEncode cryptToken before creating cookie. See Google Issue # 144, // which was marked as "WontFix". Cookie cookie = new Cookie( REMEMBER_TOKEN_COOKIE_NAME, cryptToken ); cookie.setMaxAge( maxAge ); cookie.setDomain( domain ); cookie.setPath( path ); cookie.setHttpOnly(forceHttpOnly); cookie.setSecure(forceSecureCookies); response.addCookie( cookie ); logger.info(Logger.SECURITY_SUCCESS, "Enabled remember me token for " + user.getAccountName() ); return cryptToken; } catch( IntegrityException e ) { logger.warning(Logger.SECURITY_FAILURE, "Attempt to set remember me token failed for " + user.getAccountName(), e ); return null; } } public String setRememberToken(HttpServletRequest request, HttpServletResponse response, int maxAge, String domain, String path){ String rval = ""; User user = ESAPI.authenticator().getCurrentUser(); try{ killCookie(request,response, REMEMBER_TOKEN_COOKIE_NAME); // seal already contains random data String clearToken = user.getAccountName(); long expiry = ESAPI.encryptor().getRelativeTimeStamp(maxAge * 1000); String cryptToken = ESAPI.encryptor().seal(clearToken, expiry); SecurityConfiguration sg = ESAPI.securityConfiguration(); boolean forceSecureCookies = sg.getBooleanProp("HttpUtilities.ForceSecureCookies"); boolean forceHttpOnly = sg.getBooleanProp("HttpUtilities.ForceHttpOnlyCookies"); // Do NOT URLEncode cryptToken before creating cookie. See Google Issue # 144, // which was marked as "WontFix". Cookie cookie = new Cookie( REMEMBER_TOKEN_COOKIE_NAME, cryptToken ); cookie.setMaxAge( maxAge ); cookie.setDomain( domain ); cookie.setPath( path ); cookie.setHttpOnly(forceHttpOnly); cookie.setSecure(forceSecureCookies); response.addCookie( cookie ); logger.info(Logger.SECURITY_SUCCESS, "Enabled remember me token for " + user.getAccountName() ); } catch( IntegrityException e){ logger.warning(Logger.SECURITY_FAILURE, "Attempt to set remember me token failed for " + user.getAccountName(), e ); return null; } return rval; } /** * {@inheritDoc} */ public String setRememberToken( String password, int maxAge, String domain, String path ) { return setRememberToken( getCurrentRequest(), getCurrentResponse(), password, maxAge, domain, path ); } /** * {@inheritDoc} */ public void verifyCSRFToken() throws IntrusionException { verifyCSRFToken( getCurrentRequest() ); } /** * {@inheritDoc} * * This implementation uses the CSRF_TOKEN_NAME parameter for the token. * * @param request */ public void verifyCSRFToken(HttpServletRequest request) throws IntrusionException { User user = ESAPI.authenticator().getCurrentUser(); // check if user authenticated with this request - no CSRF protection required if( request.getAttribute(user.getCSRFToken()) != null ) { return; } String token = request.getParameter(CSRF_TOKEN_NAME); if ( !user.getCSRFToken().equals( token ) ) { throw new IntrusionException("Authentication failed", "Possibly forged HTTP request without proper CSRF token detected"); } } /** * {@inheritDoc} */ public T getSessionAttribute( String key ) { final HttpSession session = ESAPI.currentRequest().getSession(false); if ( session != null ) return (T) session.getAttribute(key); return null; } /** * {@inheritDoc} */ public T getSessionAttribute(HttpSession session, String key) { return (T) session.getAttribute(key); } /** * {@inheritDoc} */ public T getRequestAttribute(String key) { return (T) ESAPI.currentRequest().getAttribute(key); } /** * {@inheritDoc} */ public T getRequestAttribute(HttpServletRequest request, String key) { return (T) request.getAttribute( key ); } ///////////////////// /* Helper method to encrypt using new Encryptor encryption methods and * return the serialized ciphertext as a hex-encoded string. */ private String encryptString(String plaintext) throws EncryptionException { PlainText pt = new PlainText(plaintext); CipherText ct = ESAPI.encryptor().encrypt(pt); byte[] serializedCiphertext = ct.asPortableSerializedByteArray(); return Hex.encode(serializedCiphertext, false); } /* Helper method to decrypt a hex-encode serialized ciphertext string and * to decrypt it using the new Encryptor decryption methods. */ private String decryptString(String ciphertext) throws EncryptionException { byte[] serializedCiphertext = Hex.decode(ciphertext); CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(serializedCiphertext); PlainText plaintext = ESAPI.encryptor().decrypt(restoredCipherText); return plaintext.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy