From b06b1f15aca3e42710ed6a496624e649464e2281 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Thu, 3 Jan 2013 04:01:53 -0500 Subject: [PATCH 1/3] Set SSL options for increased security Disable SSLv2, SSLv3, and compression; generate new DH or ECDH keys during each handshake; always start a new session on server renegotiation; set a strong cipher list. Signed-off-by: Anders Kaseorg [ Patch from https://code.google.com/p/shellinabox/issues/detail?id=215 ] --- libhttp/ssl.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/libhttp/ssl.c b/libhttp/ssl.c index d2788dd..c932deb 100644 --- a/libhttp/ssl.c +++ b/libhttp/ssl.c @@ -583,6 +583,27 @@ static int sslSetCertificateFromFile(SSL_CTX *context, } #endif +static SSL_CTX *sslMakeContext(void) { + SSL_CTX *context; + check(context = SSL_CTX_new(SSLv23_server_method())); + SSL_CTX_set_options(context, SSL_OP_ALL); + SSL_CTX_set_options(context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); +#ifdef SSL_OP_NO_COMPRESSION + SSL_CTX_set_options(context, SSL_OP_NO_COMPRESSION); +#elif OPENSSL_VERSION_NUMBER >= 0x00908000L + sk_SSL_COMP_zero(SSL_COMP_get_compression_methods()); +#endif + SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE); +#ifdef SSL_OP_SINGLE_ECDH_USE + SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE); +#endif +#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION + SSL_CTX_set_options(context, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); +#endif + check(SSL_CTX_set_cipher_list(context, "HIGH:MEDIUM:!aNULL:!MD5")); + return context; +} + #ifdef HAVE_TLSEXT static int sslSNICallback(SSL *sslHndl, int *al ATTR_UNUSED, struct SSLSupport *ssl) { @@ -619,7 +640,7 @@ static int sslSNICallback(SSL *sslHndl, int *al ATTR_UNUSED, serverName+1, NULL); if (context == NULL) { - check(context = SSL_CTX_new(SSLv23_server_method())); + context = sslMakeContext(); check(ssl->sniCertificatePattern); char *certificate = stringPrintfUnchecked(NULL, ssl->sniCertificatePattern, @@ -697,7 +718,7 @@ void sslSetCertificate(struct SSLSupport *ssl, const char *filename, } // Try to set the default certificate. If necessary, (re-)generate it. - check(ssl->sslContext = SSL_CTX_new(SSLv23_server_method())); + ssl->sslContext = sslMakeContext(); if (autoGenerateMissing) { if (sslSetCertificateFromFile(ssl->sslContext, defaultCertificate) < 0) { char hostname[256], buf[4096]; @@ -781,7 +802,7 @@ static char *sslFdToFilename(int fd) { void sslSetCertificateFd(struct SSLSupport *ssl, int fd) { #ifdef HAVE_OPENSSL - check(ssl->sslContext = SSL_CTX_new(SSLv23_server_method())); + ssl->sslContext = sslMakeContext(); char *filename = sslFdToFilename(fd); if (!sslSetCertificateFromFd(ssl->sslContext, fd)) { fatal("Cannot read valid certificate from %s. Check file format.", From 490781d998688125505dd56b6b52187644864005 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 10 Dec 2014 20:05:00 +0000 Subject: [PATCH 2/3] Add dynamic linking for functions required by SSL v2/3 disabling patch. --- libhttp/ssl.c | 16 +++++++++++++++- libhttp/ssl.h | 6 ++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libhttp/ssl.c b/libhttp/ssl.c index c932deb..b96f9d9 100644 --- a/libhttp/ssl.c +++ b/libhttp/ssl.c @@ -136,6 +136,9 @@ int (*SSL_write)(SSL *, const void *, int); SSL_METHOD * (*SSLv23_server_method)(void); X509 * (*d2i_X509)(X509 **px, const unsigned char **in, int len); void (*X509_free)(X509 *a); +int (*x_SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str); +void (*x_sk_zero)(void *st); +void * (*x_SSL_COMP_get_compression_methods)(void); #endif static void sslDestroyCachedContext(void *ssl_, char *context_) { @@ -308,7 +311,9 @@ static void loadSSL(void) { { { &SSL_write }, "SSL_write" }, { { &SSLv23_server_method }, "SSLv23_server_method" }, { { &d2i_X509 }, "d2i_X509" }, - { { &X509_free }, "X509_free" } + { { &X509_free }, "X509_free" }, + { { &x_SSL_CTX_set_cipher_list }, "SSL_CTX_set_cipher_list" }, + { { &x_sk_zero }, "sk_zero" } }; for (unsigned i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) { if (!(*symbols[i].var = loadSymbol(path_libssl, symbols[i].fn))) { @@ -320,6 +325,10 @@ static void loadSSL(void) { return; } } + // These are optional + x_SSL_COMP_get_compression_methods = loadSymbol(path_libssl, "SSL_COMP_get_compression_methods"); + // ends + SSL_library_init(); dcheck(!ERR_peek_error()); debug("Loaded SSL suppport"); @@ -590,6 +599,11 @@ static SSL_CTX *sslMakeContext(void) { SSL_CTX_set_options(context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options(context, SSL_OP_NO_COMPRESSION); +#endif +#if defined(HAVE_DLOPEN) + if (SSL_COMP_get_compression_methods) { + sk_SSL_COMP_zero(SSL_COMP_get_compression_methods()); + } #elif OPENSSL_VERSION_NUMBER >= 0x00908000L sk_SSL_COMP_zero(SSL_COMP_get_compression_methods()); #endif diff --git a/libhttp/ssl.h b/libhttp/ssl.h index 62d585b..e1477ab 100644 --- a/libhttp/ssl.h +++ b/libhttp/ssl.h @@ -111,6 +111,9 @@ extern int (*x_SSL_write)(SSL *, const void *, int); extern SSL_METHOD *(*x_SSLv23_server_method)(void); extern X509 * (*x_d2i_X509)(X509 **px, const unsigned char **in, int len); extern void (*x_X509_free)(X509 *a); +extern int (*x_SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str); +extern void (*x_sk_zero)(void *st); +extern void *(*x_SSL_COMP_get_compression_methods)(void); #define BIO_ctrl x_BIO_ctrl #define BIO_f_buffer x_BIO_f_buffer @@ -151,6 +154,9 @@ extern void (*x_X509_free)(X509 *a); #define SSLv23_server_method x_SSLv23_server_method #define d2i_X509 x_d2i_X509 #define X509_free x_X509_free +#define SSL_CTX_set_cipher_list x_SSL_CTX_set_cipher_list +#define sk_zero x_sk_zero +#define SSL_COMP_get_compression_methods x_SSL_COMP_get_compression_methods #undef BIO_set_buffer_read_data #undef SSL_CTX_set_tlsext_servername_arg From 97521bbfebcdb40110416b65e0ff4a4d2e759b91 Mon Sep 17 00:00:00 2001 From: KLuka Date: Thu, 5 Mar 2015 18:34:21 +0100 Subject: [PATCH 3/3] Issue #275: gracefully manage HTTP time-outs and connection problems Patch reference: e69132f3762bd57a328dfc40b645d670d651afe7 Patch message: When connecting to shellinabox through an HTTP Proxy, we need to be careful in holding the HTTP/S connection with unbound pending HTTP-POST as they would occupy one thread in the outbound proxy. We do need to make sure that: - HTTP POST will graceful time-out from the client side, if no data is returned by the server in 30s (gives the impression to the HTTP Proxy that the "page load" is completed after tha time and then would release the thread) - In case of connection errors, the browser doesn't retry with a short loop but waits 1s before trying again. This prevent the browser freezing and the CPU looping. --- shellinabox/shell_in_a_box.jspp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/shellinabox/shell_in_a_box.jspp b/shellinabox/shell_in_a_box.jspp index de7e5be..5b3825a 100644 --- a/shellinabox/shell_in_a_box.jspp +++ b/shellinabox/shell_in_a_box.jspp @@ -164,6 +164,7 @@ ShellInABox.prototype.sendRequest = function(request) { request = new XMLHttpRequest(); } request.open('POST', this.url + '?', true); + request.timeout = 30000; // Don't leave POST pending forever: force 30s timeout to prevent HTTP Proxy thread hijack request.setRequestHeader('Cache-Control', 'no-cache'); request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8'); @@ -202,8 +203,12 @@ ShellInABox.prototype.onReadyStateChange = function(request) { this.sendRequest(request); } } else if (request.status == 0) { - // Time Out - this.sendRequest(request); + // Time Out or other connection problems: retry after 1s to prevent release CPU before retry + setTimeout(function(shellInABox) { + return function() { + shellInABox.sendRequest(); + }; + }(this), 1000); } else { this.sessionClosed(); }