diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | freebsd/Makefile | 1 | ||||
-rw-r--r-- | hsts-preload | 108 | ||||
-rw-r--r-- | linux/Makefile | 3 | ||||
-rw-r--r-- | settings.c | 35 | ||||
-rw-r--r-- | unix.c | 2 | ||||
-rw-r--r-- | whitelist.c | 6 | ||||
-rw-r--r-- | xombrero.1 | 20 | ||||
-rw-r--r-- | xombrero.c | 44 | ||||
-rw-r--r-- | xombrero.conf | 10 | ||||
-rw-r--r-- | xombrero.h | 9 |
11 files changed, 228 insertions, 11 deletions
diff --git a/Makefile b/Makefile index 5867dcb..e9ada1a 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,7 @@ beforeinstall: install -m 644 ${.CURDIR}/xombreroicon128.png ${PREFIX}/share/xombrero install -m 644 ${.CURDIR}/tld-rules ${PREFIX}/share/xombrero install -m 644 ${.CURDIR}/style.css ${PREFIX}/share/xombrero + install -m 644 ${.CURDIR}/hsts-preload ${PREFIX}/share/xombrero ${PROG} ${OBJS} beforedepend: javascript.h diff --git a/freebsd/Makefile b/freebsd/Makefile index a6be6af..9ed119b 100644 --- a/freebsd/Makefile +++ b/freebsd/Makefile @@ -72,6 +72,7 @@ install: all install -m 644 ../xombreroicon128.png $(DESTDIR)$(RESDIR) install -m 644 ../tld-rules $(DESTDIR)$(RESDIR) install -m 644 ../style.css $(DESTDIR)$(RESDIR) + install -m 644 ../hsts-preload $(DESTDIR)$(RESDIR) clean: rm -f xombrero *.o diff --git a/hsts-preload b/hsts-preload new file mode 100644 index 0000000..5bff60d --- /dev/null +++ b/hsts-preload @@ -0,0 +1,108 @@ +force_https = bitbucket.org +force_https = .bitrig.org +force_https = .conformal.com +force_https = .conformalsys.org +force_https = .cyphertite.com +force_https = .defcon.org +force_https = duck.co +force_https = .eff.org +force_https = github.com +force_https = gist.github.com +force_https = bugzilla.gnome.org +force_https = lobste.rs +force_https = .bugzilla.mozilla.org +force_https = mtgox.com +force_https = gitweb.torproject.org +force_https = twitter.com + +# sites from chromium's preloaded HSTS list +# http://src.chromium.org/viewvc/chrome/trunk/src/net/base/transport_security_state_static.json?view=markup +force_https = .market.android.com +force_https = .ssl.google-analytics.com +force_https = .googleplex.com +force_https = www.paypal.com +force_https = www.elanex.biz +force_https = .jottit.com +force_https = .sunshinepress.org +force_https = www.noisebridge.net +force_https = .neg9.org +force_https = .riseup.net +force_https = factor.cc +force_https = members.mayfirst.org +force_https = support.mayfirst.org +force_https = id.mayfirst.org +force_https = lists.mayfirst.org +force_https = aladdinschools.appspot.com +force_https = .ottospora.nl +force_https = www.paycheckrecords.com +force_https = lastpass.com +force_https = www.lastpass.com +force_https = .keyerror.com +force_https = entropia.de +force_https = www.entropia.de +force_https = .romab.com +force_https = logentries.com +force_https = www.logentries.com +force_https = .stripe.com +force_https = .cloudsecurityalliance.org +force_https = .login.sapo.pt +force_https = .mattmccutchen.net +force_https = .betnet.fr +force_https = .uprotect.it +force_https = squareup.com +force_https = .cert.se +force_https = .crypto.is +force_https = .simon.butcher.name +force_https = .linx.net +force_https = dropcam.com +force_https = www.dropcam.com +force_https = .ebanking.indovinabank.com.vn +force_https = epoxate.com +force_https = torproject.org +force_https = .blog.torproject.org +force_https = .check.torproject.org +force_https = .www.torproject.org +force_https = .www.moneybookers.com +force_https = ledgerscope.net +force_https = www.ledgerscope.net +force_https = kyps.net +force_https = www.kyps.net +force_https = .app.recurly.com +force_https = .api.recurly.com +force_https = greplin.com +force_https = www.greplin.com +force_https = .luneta.nearbuysystems.com +force_https = .ubertt.org +force_https = .pixi.me +force_https = .grepular.com +force_https = mydigipass.com +force_https = www.mydigipass.com +force_https = developer.mydigipass.com +force_https = www.developer.mydigipass.com +force_https = sandbox.mydigipass.com +force_https = www.sandbox.mydigipass.com +force_https = .crypto.cat +force_https = .bigshinylock.minazo.net +force_https = .crate.io +force_https = .braintreegateway.com +force_https = braintreepayments.com +force_https = www.braintreepayments.com +force_https = emailprivacytester.com +force_https = .business.medbank.com.mt +force_https = .arivo.com.br +force_https = .www.apollo-auto.com +force_https = .www.cueup.com +force_https = jitsi.org +force_https = www.jitsi.org +force_https = download.jitsi.org +force_https = .sol.io +force_https = irccloud.com +force_https = www.irccloud.com +force_https = alpha.irccloud.com +force_https = .passwd.io +force_https = .browserid.org +force_https = .login.persona.org +force_https = gmail.com +force_https = googlemail.com +force_https = www.gmail.com +force_https = www.googlemail.com diff --git a/linux/Makefile b/linux/Makefile index c0c2455..8d4e3cf 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -61,6 +61,7 @@ install: all install -m 644 ../xombreroicon128.png $(DESTDIR)$(RESDIR) install -m 644 ../tld-rules $(DESTDIR)$(RESDIR) install -m 644 ../style.css $(DESTDIR)$(RESDIR) + install -m 644 ../hsts-preload $(DESTDIR)$(RESDIR) uninstall: rm -f $(DESTDIR)$(BINDIR)/xombrero @@ -71,7 +72,9 @@ uninstall: rm -f $(DESTDIR)$(RESDIR)/xombreroicon48.png rm -f $(DESTDIR)$(RESDIR)/xombreroicon64.png rm -f $(DESTDIR)$(RESDIR)/xombreroicon128.png + rm -f $(DESTDIR)$(RESDIR)/tld-rules rm -f $(DESTDIR)$(RESDIR)/style.css + rm -f $(DESTDIR)$(RESDIR)/hsts-preload if [ -d $(DESTDIR)$(RESDIR) ]; then rmdir $(DESTDIR)$(RESDIR); fi clean: rm -f xombrero $(OBJS) $(DEPS) diff --git a/settings.c b/settings.c index 053d145..0850b4e 100644 --- a/settings.c +++ b/settings.c @@ -112,6 +112,7 @@ int warn_cert_changes = 0; int allow_insecure_content = XT_DS_ALLOW_INSECURE_CONTENT; int allow_insecure_scripts = XT_DS_ALLOW_INSECURE_SCRIPTS; int do_not_track = XT_DS_DO_NOT_TRACK; +int preload_strict_transport = XT_DS_PRELOAD_STRICT_TRANSPORT; char *cmd_font_name = NULL; /* these are all set at startup */ char *oops_font_name = NULL; @@ -140,6 +141,7 @@ int add_ua(struct settings *, char *); int add_http_accept(struct settings *, char *); int add_cmd_alias(struct settings *, char *); int add_custom_uri(struct settings *, char *); +int add_force_https(struct settings *, char *); int set_append_next(char *); int set_autofocus_onload(char *); @@ -226,6 +228,8 @@ void walk_cmd_alias(struct settings *, void (*)(struct settings *, char *, void *), void *); void walk_custom_uri(struct settings *, void (*)(struct settings *, char *, void *), void *); +void walk_force_https(struct settings *, void (*)(struct settings *, + char *, void *), void *); int set_http_proxy(char *proxy) @@ -395,6 +399,12 @@ struct special s_userstyle = { NULL }; +struct special s_force_https = { + add_force_https, + NULL, + walk_force_https +}; + struct settings rs[] = { { "allow_insecure_content", XT_S_INT, 0, &allow_insecure_content, NULL, NULL, NULL, set_allow_insecure_content }, { "allow_insecure_scripts", XT_S_INT, 0, &allow_insecure_scripts, NULL, NULL, NULL, set_allow_insecure_scripts }, @@ -442,6 +452,7 @@ struct settings rs[] = { { "max_connections", XT_S_INT, XT_SF_RESTART,&max_connections, NULL, NULL, NULL, NULL }, { "max_host_connections", XT_S_INT, XT_SF_RESTART,&max_host_connections, NULL, NULL, NULL, NULL }, { "oops_font", XT_S_STR, 0, NULL, &oops_font_name, NULL, NULL, set_oops_font }, + { "preload_strict_transport", XT_S_INT, 0, &preload_strict_transport, NULL, NULL, NULL, NULL }, { "read_only_cookies", XT_S_INT, 0, &read_only_cookies, NULL, NULL, NULL, set_read_only_cookies }, { "referer", XT_S_STR, 0, NULL, NULL,&s_referer, NULL, set_referer_rt }, { "refresh_interval", XT_S_INT, 0, &refresh_interval, NULL, NULL, NULL, set_refresh_interval }, @@ -478,6 +489,7 @@ struct settings rs[] = { { "cmd_alias", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_cmd_alias, NULL, NULL }, { "cookie_wl", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_cookie_wl, NULL, NULL }, { "custom_uri", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_uri, NULL, NULL }, + { "force_https", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_force_https, NULL, NULL }, { "http_accept", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_http_accept, NULL, NULL }, { "js_wl", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_js, NULL, NULL }, { "keybinding", XT_S_STR, XT_SF_RUNTIME, NULL, NULL, &s_kb, NULL, NULL }, @@ -1476,6 +1488,14 @@ walk_ua(struct settings *s, } int +add_force_https(struct settings *s, char *value) +{ + wl_add(value, &force_https, + XT_WL_FLAG_HANDY | XT_WL_FLAG_EXCLUDE_SUBDOMAINS); + return (0); +} + +int add_http_accept(struct settings *s, char *value) { struct http_accept *ha; @@ -2582,6 +2602,21 @@ walk_pl_wl(struct settings *s, cb(s, d->d, cb_args); } +void +walk_force_https(struct settings *s, + void (*cb)(struct settings *, char *, void *), void *cb_args) +{ + struct domain *d; + + if (s == NULL || cb == NULL) { + show_oops(NULL, "walk_force_https invalid parameters"); + return; + } + + RB_FOREACH_REVERSE(d, domain_list, &force_https) + cb(s, d->d, cb_args); +} + int settings_add(char *var, char *val) { diff --git a/unix.c b/unix.c index e7a883e..93d0b1c 100644 --- a/unix.c +++ b/unix.c @@ -19,7 +19,7 @@ void init_unix(void) { - resource_dir = g_strdup("/usr/local/share/xombrero/"); + resource_dir = g_strdup("/usr/local/share/xombrero"); } void (*os_init)(void) = init_unix; diff --git a/whitelist.c b/whitelist.c index 9719dac..2c3ee01 100644 --- a/whitelist.c +++ b/whitelist.c @@ -266,7 +266,7 @@ wl_show(struct tab *t, struct karg *args, char *title, struct domain_list *wl) } void -wl_add(char *str, struct domain_list *wl, int handy) +wl_add(const char *str, struct domain_list *wl, int flags) { struct domain *d; int add_dot = 0; @@ -282,7 +282,7 @@ wl_add(char *str, struct domain_list *wl, int handy) str = &str[1]; else if (str[0] == '.') str = &str[0]; - else + else if (!(flags & XT_WL_FLAG_EXCLUDE_SUBDOMAINS)) add_dot = 1; /* slice off port number */ @@ -295,7 +295,7 @@ wl_add(char *str, struct domain_list *wl, int handy) d->d = g_strdup_printf(".%s", str); else d->d = g_strdup(str); - d->handy = handy; + d->handy = flags & XT_WL_FLAG_HANDY; if (RB_INSERT(domain_list, wl, d)) goto unwind; diff --git a/xombrero.1 b/xombrero.1 index 6cf5c27..a896599 100644 --- a/xombrero.1 +++ b/xombrero.1 @@ -1232,6 +1232,14 @@ Enables a backward, forward, and stop button to the toolbar. Additionally if .Cm search_string is set it'll enable an entry box for searches. +.It Cm force_https +This setting is used to define the domains of sites that should be +only accessed over the HTTPS scheme. +Any requests to these domains over HTTP will be rewritten to use HTTPS +instead. +See +.Cm cookie_wl +for semantics. .It Cm guess_search When enabled .Nm @@ -1365,6 +1373,18 @@ This is a plugin whitelist item. See .Cm cookie_wl for semantics and more details. +.It Cm preload_strict_transport +If enabled, a preloaded list of sites which set the HTTP Strict +Transport Security header will be used to automatically set the +.Cm force_https +setting for these sites. +This is used to prevent SSL stripping attacks when first visiting +these sites, before they have been added to the strict-transport file. +This list is comprised of domains chosen by the +.Nm +authors, as well as domains included in Chromium's preloaded HSTS +list. +Default is 1. .It Cm read_only_cookies Mark cookies file read-only and discard all cookies once the session is terminated. diff --git a/xombrero.c b/xombrero.c index 439b367..b215e32 100644 --- a/xombrero.c +++ b/xombrero.c @@ -216,6 +216,7 @@ struct session_list sessions; struct domain_list c_wl; struct domain_list js_wl; struct domain_list pl_wl; +struct domain_list force_https; struct strict_transport_tree st_tree; struct undo_tailq undos; struct keybinding_list kbl; @@ -4722,6 +4723,20 @@ corrupt_file: return (1); } +int +force_https_check(const char *uri) +{ + struct domain *d = NULL; + + if (uri == NULL) + return (0); + + if ((d = wl_find_uri(uri, &force_https)) == NULL) + return (0); + else + return (1); +} + void strict_transport_security_cb(SoupMessage *msg, gpointer data) { @@ -4918,19 +4933,23 @@ webview_rrs_cb(WebKitWebView *wv, WebKitWebFrame *wf, WebKitWebResource *res, WebKitNetworkRequest *request, WebKitNetworkResponse *response, struct tab *t) { - SoupMessage *msg; - SoupURI *uri; - struct http_accept ha_find, *ha; - const char *accept; + SoupMessage *msg = NULL; + SoupURI *uri = NULL; + struct http_accept ha_find, *ha = NULL; + const char *accept = NULL; + char *uri_s = NULL; msg = webkit_network_request_get_message(request); if (!msg) return; uri = soup_message_get_uri(msg); - if (!uri) return; + if (!uri) + return; + uri_s = soup_uri_to_string(uri, FALSE); if (strcmp(uri->scheme, SOUP_URI_SCHEME_HTTP) == 0) { - if (strict_transport_check(uri->host)) { + if (strict_transport_check(uri->host) || + force_https_check(uri_s)) { DNPRINTF(XT_D_NAV, "webview_rrs_cb: force https for %s\n", uri->host); soup_uri_set_scheme(uri, SOUP_URI_SCHEME_HTTPS); @@ -4946,7 +4965,7 @@ webview_rrs_cb(WebKitWebView *wv, WebKitWebFrame *wf, WebKitWebResource *res, "Accept"); if (accept == NULL || strncmp(accept, "text/html", strlen("text/html"))) - return; + goto done; ha_find.id = t->http_accept_id; ha = RB_FIND(http_accept_list, &ha_list, &ha_find); @@ -4963,6 +4982,9 @@ webview_rrs_cb(WebKitWebView *wv, WebKitWebFrame *wf, WebKitWebResource *res, soup_message_headers_replace(msg->request_headers, "Accept", http_accept->value); } +done: + if (uri_s) + g_free(uri_s); } WebKitWebView * @@ -8365,6 +8387,7 @@ main(int argc, char **argv) RB_INIT(&hl); RB_INIT(&js_wl); RB_INIT(&pl_wl); + RB_INIT(&force_https); RB_INIT(&downloads); RB_INIT(&st_tree); RB_INIT(&svl); @@ -8494,6 +8517,13 @@ main(int argc, char **argv) pwd->pw_dir, XT_CONF_FILE); config_parse(conf, 0); + /* read preloaded HSTS list */ + if (preload_strict_transport) { + snprintf(conf, sizeof conf, "%s" PS "%s", + resource_dir, XT_HSTS_PRELOAD_FILE); + config_parse(conf, 0); + } + /* init fonts */ cmd_font = pango_font_description_from_string(cmd_font_name); oops_font = pango_font_description_from_string(oops_font_name); diff --git a/xombrero.conf b/xombrero.conf index b3643c4..f04eddb 100644 --- a/xombrero.conf +++ b/xombrero.conf @@ -59,6 +59,7 @@ # userstyle_global = 1 # enable_favicon_entry = 0 # enable_favicon_tabs = 1 +# preload_strict_transport = 1 # referer = always # warn_cert_changes = 1 @@ -146,6 +147,15 @@ ## +## FORCE HTTPS FOR SITES +## + +# Add the domains of sites that should be only accesed over HTTPS. + +# force_https = .conformal.com + + +## ## MIME TYPES ## diff --git a/xombrero.h b/xombrero.h index 218d712..cd8f4c7 100644 --- a/xombrero.h +++ b/xombrero.h @@ -370,6 +370,7 @@ RB_PROTOTYPE(http_accept_list, http_accept, entry, http_accept_rb_cmp); #define XT_CSS_FILE ("xombrero.css") #define XT_FAVS_FILE ("favorites") #define XT_SOD_FILE ("startofday") +#define XT_HSTS_PRELOAD_FILE ("hsts-preload") #define XT_RESERVED_CHARS "$&+,/:;=?@ \"<>#%%{}|^~[]`" int run_script(struct tab *, char *); @@ -525,6 +526,9 @@ void startpage_add(const char *, ...); #define XT_WL_COOKIE (2) #define XT_WL_PLUGIN (3) +#define XT_WL_FLAG_HANDY (1<<0) +#define XT_WL_FLAG_EXCLUDE_SUBDOMAINS (1<<1) + struct domain { RB_ENTRY(domain) entry; gchar *d; @@ -648,6 +652,7 @@ int command_mode(struct tab *, struct karg *); #define XT_DS_ALLOW_INSECURE_CONTENT (TRUE) #define XT_DS_ALLOW_INSECURE_SCRIPTS (TRUE) #define XT_DS_DO_NOT_TRACK (0) +#define XT_DS_PRELOAD_STRICT_TRANSPORT (1) /* actions */ @@ -739,6 +744,8 @@ int cert_cmd(struct tab *, struct karg *); void focus_webview(struct tab *); int is_g_object_setting(GObject *, char *); int set_scrollbar_visibility(struct tab *, int); +void wl_add(const char *, struct domain_list *, int); +void preload_hsts(void); #define XT_DL_START (0) #define XT_DL_RESTART (1) @@ -828,6 +835,7 @@ extern regex_t url_re; extern int allow_insecure_content; extern int allow_insecure_scripts; extern int do_not_track; +extern int preload_strict_transport; /* globals */ extern void (*os_init)(void); @@ -854,6 +862,7 @@ extern struct about_type about_list[]; extern struct domain_list c_wl; extern struct domain_list js_wl; extern struct domain_list pl_wl; +extern struct domain_list force_https; extern struct strict_transport_tree st_tree; extern struct alias_list aliases; extern struct mime_type_list mtl; |