mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
strict host check vhost flag
https://github.com/warmcat/libwebsockets/issues/1423 If you vhost->options has the flag LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK, then if the server is sent an upgrade request, the content of the Host: header is required to match the vhost name + port. The port is set to the well-known values of 80 and 443 if no :port on the host: value, depending on tls or not on the connection. minimal-ws-server can now take a -h flag to set this. lejp-conf (eg, lwsws) can now take a flag strict-host-check on the vhost to enable it as well.
This commit is contained in:
parent
97f9af5e3b
commit
f6ae0edf8d
7 changed files with 104 additions and 8 deletions
|
@ -134,6 +134,17 @@ enum lws_context_options {
|
|||
* example the ACME plugin was configured to fetch a cert, this lets
|
||||
* you bootstrap your vhost from having no cert to start with.
|
||||
*/
|
||||
LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK = (1 << 27),
|
||||
/**< (VH) On this vhost, if the connection is being upgraded, insist
|
||||
* that there's a Host: header and that the contents match the vhost
|
||||
* name + port (443 / 80 are assumed if no :port given based on if the
|
||||
* connection is using TLS).
|
||||
*
|
||||
* By default, without this flag, on upgrade lws just checks that the
|
||||
* Host: header was given without checking the contents... this is to
|
||||
* allow lax hostname mappings like localhost / 127.0.0.1, and CNAME
|
||||
* mappings like www.mysite.com / mysite.com
|
||||
*/
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
};
|
||||
|
|
|
@ -109,6 +109,7 @@ static const char * const paths_vhosts[] = {
|
|||
"vhosts[].ssl-client-option-clear",
|
||||
"vhosts[].tls13-ciphers",
|
||||
"vhosts[].client-tls13-ciphers",
|
||||
"vhosts[].strict-host-check",
|
||||
};
|
||||
|
||||
enum lejp_vhost_paths {
|
||||
|
@ -164,6 +165,7 @@ enum lejp_vhost_paths {
|
|||
LEJPVP_SSL_CLIENT_OPTION_CLEAR,
|
||||
LEJPVP_TLS13_CIPHERS,
|
||||
LEJPVP_CLIENT_TLS13_CIPHERS,
|
||||
LEJPVP_FLAG_STRICT_HOST_CHECK,
|
||||
};
|
||||
|
||||
static const char * const parser_errs[] = {
|
||||
|
@ -754,6 +756,15 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
|
|||
|
||||
return 0;
|
||||
|
||||
case LEJPVP_FLAG_STRICT_HOST_CHECK:
|
||||
if (arg_to_bool(ctx->buf))
|
||||
a->info->options |=
|
||||
LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK;
|
||||
else
|
||||
a->info->options &=
|
||||
~(LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK);
|
||||
return 0;
|
||||
|
||||
case LEJPVP_ERROR_DOCUMENT_404:
|
||||
a->info->error_document_404 = a->p;
|
||||
break;
|
||||
|
|
|
@ -1545,6 +1545,75 @@ transaction_result_n:
|
|||
return lws_http_transaction_completed(wsi);
|
||||
}
|
||||
|
||||
int
|
||||
lws_confirm_host_header(struct lws *wsi)
|
||||
{
|
||||
struct lws_tokenize ts;
|
||||
lws_tokenize_elem e;
|
||||
char buf[128];
|
||||
int port = 80;
|
||||
|
||||
/*
|
||||
* this vhost wants us to validate what the
|
||||
* client sent against our vhost name
|
||||
*/
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
|
||||
lwsl_info("%s: missing host on upgrade\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
if (wsi->tls.ssl)
|
||||
port = 443;
|
||||
#endif
|
||||
|
||||
lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_DOT_NONTERM /* server.com */|
|
||||
LWS_TOKENIZE_F_NO_FLOATS /* 1.server.com */|
|
||||
LWS_TOKENIZE_F_MINUS_NONTERM /* a-b.com */);
|
||||
ts.len = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_HOST);
|
||||
if (ts.len <= 0) {
|
||||
lwsl_info("%s: missing or oversize host header\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lws_tokenize(&ts) != LWS_TOKZE_TOKEN)
|
||||
goto bad_format;
|
||||
|
||||
if (strncmp(ts.token, wsi->vhost->name, ts.token_len)) {
|
||||
buf[(ts.token - buf) + ts.token_len] = '\0';
|
||||
lwsl_info("%s: '%s' in host hdr but vhost name %s\n",
|
||||
__func__, ts.token, wsi->vhost->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
e = lws_tokenize(&ts);
|
||||
if (e == LWS_TOKZE_DELIMITER && ts.token[0] == ':') {
|
||||
if (lws_tokenize(&ts) != LWS_TOKZE_INTEGER)
|
||||
goto bad_format;
|
||||
else
|
||||
port = atoi(ts.token);
|
||||
} else
|
||||
if (e != LWS_TOKZE_ENDED)
|
||||
goto bad_format;
|
||||
|
||||
if (wsi->vhost->listen_port != port) {
|
||||
lwsl_info("%s: host port %d mismatches vhost port %d\n",
|
||||
__func__, port, wsi->vhost->listen_port);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_debug("%s: host header OK\n", __func__);
|
||||
|
||||
return 0;
|
||||
|
||||
bad_format:
|
||||
lwsl_info("%s: bad host header format\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
|
||||
{
|
||||
|
@ -1733,6 +1802,11 @@ raw_transition:
|
|||
|
||||
/* callback said 0, it was allowed */
|
||||
|
||||
if (wsi->vhost->options &
|
||||
LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK &&
|
||||
lws_confirm_host_header(wsi))
|
||||
goto bail_nuke_ah;
|
||||
|
||||
if (!strcasecmp(up, "websocket")) {
|
||||
#if defined(LWS_ROLE_WS)
|
||||
wsi->vhost->conn_stats.ws_upg++;
|
||||
|
|
|
@ -315,14 +315,6 @@ bad_conn_format:
|
|||
}
|
||||
} while (e > 0);
|
||||
|
||||
/* let's also confirm that Host at least exists for h1 */
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
|
||||
lwsl_err("%s: missing host: hdr on h1 ws upgrade\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
check_protocol:
|
||||
#endif
|
||||
|
|
|
@ -76,6 +76,9 @@ int main(int argc, const char **argv)
|
|||
info.ssl_cert_filepath = "localhost-100y.cert";
|
||||
info.ssl_private_key_filepath = "localhost-100y.key";
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-h"))
|
||||
info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
|
|
|
@ -12,6 +12,7 @@ Option|Meaning
|
|||
---|---
|
||||
-d|Set logging verbosity
|
||||
-s|Serve using TLS selfsigned cert (ie, connect to it with https://...)
|
||||
-h|Strict Host: header checking against vhost name (localhost) and port
|
||||
|
||||
## usage
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ int main(int argc, const char **argv)
|
|||
info.port = 7681;
|
||||
info.mounts = &mount;
|
||||
info.protocols = protocols;
|
||||
info.vhost_name = "localhost";
|
||||
info.ws_ping_pong_interval = 10;
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-s")) {
|
||||
|
@ -88,6 +89,9 @@ int main(int argc, const char **argv)
|
|||
info.ssl_private_key_filepath = "localhost-100y.key";
|
||||
}
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-h"))
|
||||
info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
|
|
Loading…
Add table
Reference in a new issue