diff --git a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc index de77a563429..3510224f181 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc @@ -26,9 +26,31 @@ Which browser/OS supports which protocols can be https://en.wikipedia.org/wiki/T * TLS v1.1 and v1.2: The protocols which should be used wherever possible. All CBC based ciphers are supported since Java 7, the new GCM modes are supported since Java 8. -* TLS v1.0: Still supported but is affected by the link:https://cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2014-3566[POODLE attack.] - To support older browsers this protocol version is still needed. -* SSL v3: is now deprecated and should *only* be enabled if you still need to support very old browsers like Internet Explorer 6 on Windows XP which does not support TLS 1.0 (or is disabled by default). + +===== Older Protocols + +Both TLS v1.0 and SSL v3 are no longer supported by default. If your Jetty implementation requires these protocols for legacy support, they can be enabled manually. + +____ +[NOTE] +Once TLS v1.3 is released, there will be no workaround available for TLS v1.0. +Plans for TLS v1.3 include banning ciphers with known vulnerabilities from being present at any level. +It is recommended to upgrade any clients using these ciphers as soon as possible or face being locked into a outdated version of Jetty, Java or even OS. +____ + +By default, Jetty exclused these ciphers in the link:{GITBROWSEURL}/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java#L253-L256[`SslContextFactory`.] +You can re-enable these by re-declaring the ciphers you want excluded in code: + +[source, java, subs="{sub-order}"] +---- +SslContextFactory sslContextFactory = new SslContextFactory(); +sslContextFactory.setExcludeCipherSuites( + "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); +---- + +If, after making these changes, you still have issues using these ciphers they are likely being blocked at the JVM level. +Locate the `$JAVA_HOME/jre/lib/security/` directory for the `java.security` file and examine it for any configuration that is excluding _ciphers_ or _algorithms_ (depending on the version of the JVM you are using the nomenclature may be different). [[understanding-certificates-and-keys]] ==== Understanding Certificates and Keys diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java index 79e2cf61956..3605f1c8c8f 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java @@ -191,6 +191,8 @@ public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent protected void customizeFastCGIHeaders(Request proxyRequest, HttpFields fastCGIHeaders) { + fastCGIHeaders.remove("HTTP_PROXY"); + fastCGIHeaders.put(FCGI.Headers.REMOTE_ADDR, (String)proxyRequest.getAttributes().get(REMOTE_ADDR_ATTRIBUTE)); fastCGIHeaders.put(FCGI.Headers.REMOTE_PORT, (String)proxyRequest.getAttributes().get(REMOTE_PORT_ATTRIBUTE)); fastCGIHeaders.put(FCGI.Headers.SERVER_NAME, (String)proxyRequest.getAttributes().get(SERVER_NAME_ATTRIBUTE)); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java index a7e745fb537..dfa794165e4 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java @@ -225,6 +225,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection @Override public void recycle() { + getStream().removeAttribute(IStream.CHANNEL_ATTRIBUTE); super.recycle(); channels.offer(this); } @@ -233,18 +234,20 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection public void onCompleted() { super.onCompleted(); - recycle(); + if (!getStream().isReset()) + recycle(); } @Override public void close() { IStream stream = getStream(); + if (LOG.isDebugEnabled()) + LOG.debug("HTTP2 Request #{}/{} rejected", stream.getId(), Integer.toHexString(stream.getSession().hashCode())); stream.reset(new ResetFrame(stream.getId(), ErrorCode.ENHANCE_YOUR_CALM_ERROR.code), Callback.NOOP); // Consume the existing queued data frames to // avoid stalling the session flow control. - getHttpTransport().consumeInput(); - recycle(); + consumeInput(); } } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 92c9f193c2e..ccea710b9b7 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -192,6 +192,17 @@ public class HttpChannelOverHTTP2 extends HttpChannel public Runnable requestContent(DataFrame frame, final Callback callback) { + Stream stream = getStream(); + if (stream.isReset()) + { + // Consume previously queued content to + // enlarge the session flow control window. + consumeInput(); + // Consume immediately this content. + callback.succeeded(); + return null; + } + // We must copy the data since we do not know when the // application will consume the bytes (we queue them by // calling onContent()), and the parsing will continue @@ -234,7 +245,6 @@ public class HttpChannelOverHTTP2 extends HttpChannel if (LOG.isDebugEnabled()) { - Stream stream = getStream(); LOG.debug("HTTP2 Request #{}/{}: {} bytes of {} content, handle: {}", stream.getId(), Integer.toHexString(stream.getSession().hashCode()), @@ -249,6 +259,11 @@ public class HttpChannelOverHTTP2 extends HttpChannel return handle || delayed ? this : null; } + protected void consumeInput() + { + getRequest().getHttpInput().consumeAll(); + } + /** * If the associated response has the Expect header set to 100 Continue, * then accessing the input stream indicates that the handler/servlet diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index cede6d447ff..c058801fd10 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -31,7 +31,6 @@ import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpTransport; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; @@ -218,17 +217,16 @@ public class HttpTransportOverHTTP2 implements HttpTransport // If the stream is not closed, it is still reading the request content. // Send a reset to the other end so that it stops sending data. if (!stream.isClosed()) + { + if (LOG.isDebugEnabled()) + LOG.debug("HTTP2 Response #{}: unconsumed request content, resetting stream", stream.getId()); stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP); + } // Consume the existing queued data frames to // avoid stalling the session flow control. - consumeInput(); - } - - protected void consumeInput() - { - HttpChannel channel = (HttpChannel)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE); - channel.getRequest().getHttpInput().consumeAll(); + HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE); + channel.consumeInput(); } @Override diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index f83d477dd10..15bc0c9deea 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -627,6 +627,15 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor protected boolean sendResponse(MetaData.Response info, ByteBuffer content, boolean complete, final Callback callback) { boolean committing = _committed.compareAndSet(false, true); + + if (LOG.isDebugEnabled()) + LOG.debug("sendResponse info={} content={} complete={} committing={} callback={}", + info, + BufferUtil.toDetailString(content), + complete, + committing, + callback); + if (committing) { // We need an info to commit diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java index 4d9ea3ee7ee..4264f9c22a1 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java @@ -84,7 +84,6 @@ public class CGI extends HttpServlet private boolean _ignoreExitState; private boolean _relative; - /* ------------------------------------------------------------ */ @Override public void init() throws ServletException { @@ -141,13 +140,13 @@ public class CGI extends HttpServlet } catch (IOException e) { - LOG.warn("CGI: CGI bin failed - " + dir,e); + LOG.warn("CGI: CGI bin failed - " + dir, e); return; } _path = getInitParameter("Path"); if (_path != null) - _env.set("PATH",_path); + _env.set("PATH", _path); _ignoreExitState = "true".equalsIgnoreCase(getInitParameter("ignoreExitState")); Enumeration e = getInitParameterNames(); @@ -155,21 +154,20 @@ public class CGI extends HttpServlet { String n = e.nextElement(); if (n != null && n.startsWith("ENV_")) - _env.set(n.substring(4),getInitParameter(n)); + _env.set(n.substring(4), getInitParameter(n)); } if (!_env.envMap.containsKey("SystemRoot")) { String os = System.getProperty("os.name"); - if (os != null && os.toLowerCase(Locale.ENGLISH).indexOf("windows") != -1) + if (os != null && os.toLowerCase(Locale.ENGLISH).contains("windows")) { - _env.set("SystemRoot","C:\\WINDOWS"); + _env.set("SystemRoot", "C:\\WINDOWS"); } } _ok = true; } - /* ------------------------------------------------------------ */ @Override public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { @@ -196,7 +194,7 @@ public class CGI extends HttpServlet File execCmd = new File(_docRoot, pathInContext); String pathInfo = pathInContext; - if(!_useFullPath) + if (!_useFullPath) { String path = pathInContext; String info = ""; @@ -205,30 +203,31 @@ public class CGI extends HttpServlet while ((path.endsWith("/") || !execCmd.exists()) && path.length() >= 0) { int index = path.lastIndexOf('/'); - path = path.substring(0,index); - info = pathInContext.substring(index,pathInContext.length()); - execCmd = new File(_docRoot,path); + path = path.substring(0, index); + info = pathInContext.substring(index, pathInContext.length()); + execCmd = new File(_docRoot, path); } - + if (path.length() == 0 || !execCmd.exists() || execCmd.isDirectory() || !execCmd.getCanonicalPath().equals(execCmd.getAbsolutePath())) { res.sendError(404); } - + pathInfo = info; } - exec(execCmd,pathInfo,req,res); + exec(execCmd, pathInfo, req, res); } - /** executes the CGI process - /* - * @param command the command to execute, this command is prefixed by - * the context parameter "commandPrefix". + /** + * executes the CGI process + * + * @param command the command to execute, this command is prefixed by + * the context parameter "commandPrefix". * @param pathInfo The PATH_INFO to process, - * see http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getPathInfo%28%29. Cannot be null - * @param req - * @param res - * @exception IOException + * see http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getPathInfo%28%29. Cannot be null + * @param req the HTTP request + * @param res the HTTP response + * @throws IOException if the execution of the CGI process throws */ private void exec(File command, String pathInfo, HttpServletRequest req, HttpServletResponse res) throws IOException { @@ -244,9 +243,9 @@ public class CGI extends HttpServlet } String bodyFormEncoded = null; - if ((HttpMethod.POST.equals(req.getMethod()) || HttpMethod.PUT.equals(req.getMethod())) && "application/x-www-form-urlencoded".equals(req.getContentType())) + if ((HttpMethod.POST.is(req.getMethod()) || HttpMethod.PUT.is(req.getMethod())) && "application/x-www-form-urlencoded".equals(req.getContentType())) { - MultiMap parameterMap = new MultiMap(); + MultiMap parameterMap = new MultiMap<>(); Enumeration names = req.getParameterNames(); while (names.hasMoreElements()) { @@ -299,15 +298,15 @@ public class CGI extends HttpServlet String scriptPath; String scriptName; // use docRoot for scriptPath, too - if(_cgiBinProvided) + if (_cgiBinProvided) { scriptPath = command.getAbsolutePath(); scriptName = scriptPath.substring(_docRoot.getAbsolutePath().length()); - } - else + } + else { String requestURI = req.getRequestURI(); - scriptName = requestURI.substring(0,requestURI.length() - pathInfo.length()); + scriptName = requestURI.substring(0, requestURI.length() - pathInfo.length()); scriptPath = getServletContext().getRealPath(scriptName); } env.set("SCRIPT_FILENAME", scriptPath); @@ -322,12 +321,14 @@ public class CGI extends HttpServlet while (enm.hasMoreElements()) { String name = enm.nextElement(); + if (name.equalsIgnoreCase("Proxy")) + continue; String value = req.getHeader(name); - env.set("HTTP_" + name.toUpperCase(Locale.ENGLISH).replace('-','_'),value); + env.set("HTTP_" + name.toUpperCase(Locale.ENGLISH).replace('-', '_'), value); } // these extra ones were from printenv on www.dev.nomura.co.uk - env.set("HTTPS", (req.isSecure()?"ON":"OFF")); + env.set("HTTPS", (req.isSecure() ? "ON" : "OFF")); // "DOCUMENT_ROOT" => root + "/docs", // "SERVER_URL" => "NYI - http://us0245", // "TZ" => System.getProperty("user.timezone"), @@ -339,13 +340,12 @@ public class CGI extends HttpServlet String execCmd = absolutePath; // escape the execCommand - if (execCmd.length() > 0 && execCmd.charAt(0) != '"' && execCmd.indexOf(" ") >= 0) + if (execCmd.length() > 0 && execCmd.charAt(0) != '"' && execCmd.contains(" ")) execCmd = "\"" + execCmd + "\""; if (_cmdPrefix != null) execCmd = _cmdPrefix + " " + execCmd; - assert execCmd != null; LOG.debug("Environment: " + env.getExportString()); LOG.debug("Command: " + execCmd); @@ -360,7 +360,7 @@ public class CGI extends HttpServlet // hook processes output to browser's input (sync) // if browser closes stream, we should detect it and kill process... OutputStream os = null; - AsyncContext async=req.startAsync(); + AsyncContext async = req.startAsync(); try { async.start(new Runnable() @@ -393,7 +393,7 @@ public class CGI extends HttpServlet int k = line.indexOf(':'); if (k > 0) { - String key = line.substring(0,k).trim(); + String key = line.substring(0, k).trim(); String value = line.substring(k + 1).trim(); if ("Location".equals(key)) { @@ -408,14 +408,14 @@ public class CGI extends HttpServlet else { // add remaining header items to our response header - res.addHeader(key,value); + res.addHeader(key, value); } } } } // copy cgi content to response stream... os = res.getOutputStream(); - IO.copy(inFromCgi,os); + IO.copy(inFromCgi, os); p.waitFor(); if (!_ignoreExitState) @@ -425,7 +425,7 @@ public class CGI extends HttpServlet { LOG.warn("Non-zero exit status (" + exitValue + ") from CGI program: " + absolutePath); if (!res.isCommitted()) - res.sendError(500,"Failed to exec CGI"); + res.sendError(500, "Failed to exec CGI"); } } } @@ -506,10 +506,9 @@ public class CGI extends HttpServlet /** * Utility method to get a line of text from the input stream. * - * @param is - * the input stream + * @param is the input stream * @return the line of text - * @throws IOException + * @throws IOException if reading from the input stream throws */ private static String getTextLineFromStream(InputStream is) throws IOException { @@ -523,7 +522,6 @@ public class CGI extends HttpServlet return buffer.toString().trim(); } - /* ------------------------------------------------------------ */ /** * private utility class that manages the Environment passed to exec. */ @@ -533,26 +531,28 @@ public class CGI extends HttpServlet EnvList() { - envMap = new HashMap(); + envMap = new HashMap<>(); } EnvList(EnvList l) { - envMap = new HashMap(l.envMap); + envMap = new HashMap<>(l.envMap); } /** * Set a name/value pair, null values will be treated as an empty String + * * @param name the name * @param value the value */ public void set(String name, String value) { - envMap.put(name,name + "=" + StringUtil.nonNull(value)); + envMap.put(name, name + "=" + StringUtil.nonNull(value)); } /** * Get representation suitable for passing to exec. + * * @return the env map as an array */ public String[] getEnvArray() @@ -578,4 +578,4 @@ public class CGI extends HttpServlet return envMap.toString(); } } -} \ No newline at end of file +}