[epiphany] Warn user about insecure password forms
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany] Warn user about insecure password forms
- Date: Sun, 27 Nov 2016 04:07:59 +0000 (UTC)
commit 5e8b6f9bc985acef72df2bec1a451a1339b75410
Author: Michael Catanzaro <mcatanzaro gnome org>
Date: Sat Nov 26 22:06:35 2016 -0600
Warn user about insecure password forms
https://bugzilla.gnome.org/show_bug.cgi?id=775167
embed/ephy-embed-shell.c | 44 ++++++++++++++++++++++++++
embed/ephy-web-view.c | 49 ++++++++++++++++++++++++++++++
embed/web-extension/ephy-web-dom-utils.c | 41 +++++++++++++++++++++++++
embed/web-extension/ephy-web-dom-utils.h | 2 +
embed/web-extension/ephy-web-extension.c | 46 ++++++++++++++++++++++++++++
lib/ephy-security-levels.c | 6 ++++
lib/ephy-security-levels.h | 2 +
7 files changed, 190 insertions(+), 0 deletions(-)
---
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index 73250cc..2ecc330 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -72,6 +72,7 @@ enum {
PAGE_CREATED,
ALLOW_TLS_CERTIFICATE,
FORM_AUTH_DATA_SAVE_REQUESTED,
+ SENSITIVE_FORM_FOCUSED,
LAST_SIGNAL
};
@@ -139,6 +140,26 @@ web_extension_form_auth_data_message_received_cb (WebKitUserContentManager *mana
}
static void
+web_extension_sensitive_form_focused_message_received_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *message,
+ EphyEmbedShell *shell)
+{
+ guint64 page_id;
+ gboolean insecure_action;
+ GVariant *variant;
+ char *message_str;
+
+ message_str = ephy_embed_utils_get_js_result_as_string (message);
+ variant = g_variant_parse (G_VARIANT_TYPE ("(tb)"), message_str, NULL, NULL, NULL);
+ g_free (message_str);
+
+ g_variant_get (variant, "(tb)", &page_id, &insecure_action);
+ g_signal_emit (shell, signals[SENSITIVE_FORM_FOCUSED], 0,
+ page_id, insecure_action);
+ g_variant_unref (variant);
+}
+
+static void
history_service_query_urls_cb (EphyHistoryService *service,
gboolean success,
GList *urls,
@@ -767,6 +788,12 @@ ephy_embed_shell_startup (GApplication *application)
shell);
webkit_user_content_manager_register_script_message_handler (priv->user_content,
+ "sensitiveFormFocused");
+ g_signal_connect (priv->user_content, "script-message-received::sensitiveFormFocused",
+ G_CALLBACK (web_extension_sensitive_form_focused_message_received_cb),
+ shell);
+
+ webkit_user_content_manager_register_script_message_handler (priv->user_content,
"aboutApps");
g_signal_connect (priv->user_content, "script-message-received::aboutApps",
G_CALLBACK (web_extension_about_apps_message_received_cb),
@@ -1031,6 +1058,23 @@ ephy_embed_shell_class_init (EphyEmbedShellClass *klass)
G_TYPE_UINT64,
G_TYPE_STRING,
G_TYPE_STRING);
+
+ /**
+ * EphyEmbedShell::sensitive-form-focused
+ * @shell: the #EphyEmbedShell
+ * @page_id: the identifier of the web page
+ * @insecure_action: whether the target of the form is http://
+ *
+ * Emitted when a form in a web page gains focus.
+ */
+ signals[SENSITIVE_FORM_FOCUSED] =
+ g_signal_new ("sensitive-form-focused",
+ EPHY_TYPE_EMBED_SHELL,
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 2,
+ G_TYPE_UINT64,
+ G_TYPE_BOOLEAN);
}
/**
diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index 90360e5..ad74394 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -101,6 +101,7 @@ struct _EphyWebView {
GtkWidget *microphone_info_bar;
GtkWidget *webcam_info_bar;
GtkWidget *password_info_bar;
+ GtkWidget *sensitive_form_info_bar;
EphyHistoryService *history_service;
GCancellable *history_service_cancellable;
@@ -736,6 +737,39 @@ form_auth_data_save_requested (EphyEmbedShell *shell,
}
static void
+sensitive_form_focused_cb (EphyEmbedShell *shell,
+ guint64 page_id,
+ gboolean insecure_action,
+ EphyWebView *web_view)
+{
+ GtkWidget *info_bar;
+ GtkWidget *label;
+ GtkWidget *content_area;
+
+ if (web_view->sensitive_form_info_bar)
+ return;
+ if (webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)) != page_id)
+ return;
+ if (insecure_action || ephy_security_level_is_secure (web_view->security_level))
+ return;
+
+ /* Translators: Message appears when insecure password form is focused. */
+ label = gtk_label_new (_("Heads-up: this form is not secure. If you type your password, it will be visible
to cybercriminals!"));
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+
+ info_bar = gtk_info_bar_new ();
+ content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar));
+ gtk_container_add (GTK_CONTAINER (content_area), label);
+ gtk_widget_show (label);
+
+ ephy_web_view_track_info_bar (info_bar, &web_view->sensitive_form_info_bar);
+
+ ephy_embed_add_top_widget (EPHY_GET_EMBED_FROM_EPHY_WEB_VIEW (web_view),
+ info_bar, FALSE);
+ gtk_widget_show (info_bar);
+}
+
+static void
allow_tls_certificate_cb (EphyEmbedShell *shell,
guint64 page_id,
EphyWebView *view)
@@ -772,6 +806,10 @@ page_created_cb (EphyEmbedShell *shell,
G_CALLBACK (form_auth_data_save_requested),
view, 0);
+ g_signal_connect_object (shell, "sensitive-form-focused",
+ G_CALLBACK (sensitive_form_focused_cb),
+ view, 0);
+
g_signal_connect_object (shell, "allow-tls-certificate",
G_CALLBACK (allow_tls_certificate_cb),
view, 0);
@@ -802,6 +840,11 @@ ephy_web_view_dispose (GObject *object)
view->password_info_bar = NULL;
}
+ if (view->sensitive_form_info_bar) {
+ g_object_remove_weak_pointer (G_OBJECT (view->sensitive_form_info_bar), (gpointer
*)&view->sensitive_form_info_bar);
+ view->sensitive_form_info_bar = NULL;
+ }
+
g_signal_handlers_disconnect_by_func (view->history_service,
ephy_web_view_history_cleared_cb,
EPHY_WEB_VIEW (object));
@@ -1634,6 +1677,12 @@ load_changed_cb (WebKitWebView *web_view,
/* Zoom level. */
restore_zoom_level (view, loading_uri);
+ if (view->sensitive_form_info_bar) {
+ g_object_remove_weak_pointer (G_OBJECT (view->sensitive_form_info_bar), (gpointer
*)&view->sensitive_form_info_bar);
+ gtk_widget_destroy (view->sensitive_form_info_bar);
+ view->sensitive_form_info_bar = NULL;
+ }
+
break;
}
case WEBKIT_LOAD_REDIRECTED:
diff --git a/embed/web-extension/ephy-web-dom-utils.c b/embed/web-extension/ephy-web-dom-utils.c
index ccc0146..41c8376 100644
--- a/embed/web-extension/ephy-web-dom-utils.c
+++ b/embed/web-extension/ephy-web-dom-utils.c
@@ -541,6 +541,47 @@ ephy_web_dom_utils_find_form_auth_elements (WebKitDOMHTMLFormElement *form,
return FALSE;
}
+/* ephy_web_dom_utils_find_form_auth_elements() is great, but it only returns
+ * something useful if it can pair a username node with a password node. This
+ * function says whether the form has a password node or not, even if Epiphany
+ * isn't smart enough to match it to a username node.
+ *
+ * Ideally we'd also detect credit card data or other sensitive stuff, but
+ * there's no standard way to do so, so don't try.
+ */
+gboolean
+ephy_web_dom_utils_form_contains_sensitive_element (WebKitDOMHTMLFormElement *form)
+{
+ WebKitDOMHTMLCollection *elements;
+ guint i, n_elements;
+ gboolean found_auth_element = FALSE;
+
+ elements = webkit_dom_html_form_element_get_elements (form);
+ n_elements = webkit_dom_html_collection_get_length (elements);
+
+ for (i = 0; i < n_elements && !found_auth_element; i++) {
+ WebKitDOMNode *element;
+ char *element_type;
+
+ element = webkit_dom_html_collection_item (elements, i);
+ if (!WEBKIT_DOM_IS_HTML_INPUT_ELEMENT (element))
+ continue;
+
+ g_object_get (element, "type", &element_type, NULL);
+
+ if (g_strcmp0 (element_type, "password") == 0 ||
+ g_strcmp0 (element_type, "adminpw") == 0) {
+ found_auth_element = TRUE;
+ }
+
+ g_free (element_type);
+ }
+
+ g_object_unref (elements);
+
+ return found_auth_element;
+}
+
/**
* ephy_web_dom_utils_get_absolute_position_for_element:
* @element: the #WebKitDOMElement.
diff --git a/embed/web-extension/ephy-web-dom-utils.h b/embed/web-extension/ephy-web-dom-utils.h
index 85c3584..ebe4c6d 100644
--- a/embed/web-extension/ephy-web-dom-utils.h
+++ b/embed/web-extension/ephy-web-dom-utils.h
@@ -39,6 +39,8 @@ gboolean ephy_web_dom_utils_find_form_auth_elements (WebKitDOMHTMLFormElement *f
WebKitDOMNode **username,
WebKitDOMNode **password);
+gboolean ephy_web_dom_utils_form_contains_sensitive_element (WebKitDOMHTMLFormElement *form);
+
void ephy_web_dom_utils_get_absolute_bottom_for_element (WebKitDOMElement *element,
double *x,
double *y);
diff --git a/embed/web-extension/ephy-web-extension.c b/embed/web-extension/ephy-web-extension.c
index c89ebd8..c176b90 100644
--- a/embed/web-extension/ephy-web-extension.c
+++ b/embed/web-extension/ephy-web-extension.c
@@ -971,6 +971,46 @@ username_node_input_cb (WebKitDOMNode *username_node,
return TRUE;
}
+static gboolean
+sensitive_form_focused_cb (WebKitDOMHTMLFormElement *form,
+ WebKitDOMEvent *dom_event,
+ WebKitWebPage *web_page)
+{
+ WebKitDOMDOMWindow *dom_window;
+ GVariant *variant;
+ char *message;
+ char *action;
+ gboolean insecure_action;
+
+ dom_window = webkit_dom_document_get_default_view (webkit_web_page_get_dom_document (web_page));
+ if (dom_window == NULL)
+ return FALSE;
+
+ action = webkit_dom_html_form_element_get_action (form);
+ /* The goal here is to detect insecure forms on secure pages. The action need
+ * not necessarily contain any protocol, so just assume the form is secure
+ * unless it's clearly not. Insecure forms on insecure pages will be detected
+ * in the UI process. Note that basically no websites should actually be dumb
+ * enough to trip this, but no doubt they exist somewhere.... */
+ insecure_action = action == NULL && g_str_has_prefix (action, "http://");
+
+ variant = g_variant_new ("(tb)",
+ webkit_web_page_get_id (web_page),
+ insecure_action);
+ message = g_variant_print (variant, FALSE);
+
+ if (!webkit_dom_dom_window_webkit_message_handlers_post_message (dom_window, "sensitiveFormFocused",
message))
+ g_warning ("Error sending sensitiveFormFocused message");
+
+ g_free (action);
+ g_free (message);
+ g_object_unref (dom_window);
+ g_variant_unref (variant);
+
+ /* Hoping FALSE means "propagate" because there is absolutely no documentation for this. */
+ return FALSE;
+}
+
static void
form_destroyed_cb (gpointer form_auth, GObject *form)
{
@@ -1059,6 +1099,12 @@ web_page_form_controls_associated (WebKitWebPage *web_page,
g_object_weak_ref (G_OBJECT (form), form_destroyed_cb, form_auth);
} else
LOG ("No pre-fillable/hookable form found");
+
+ if (ephy_web_dom_utils_form_contains_sensitive_element (form)) {
+ webkit_dom_event_target_add_event_listener (WEBKIT_DOM_EVENT_TARGET (form), "focus",
+ G_CALLBACK (sensitive_form_focused_cb), TRUE,
+ web_page);
+ }
}
}
diff --git a/lib/ephy-security-levels.c b/lib/ephy-security-levels.c
index 2cb98d2..56a40dd 100644
--- a/lib/ephy-security-levels.c
+++ b/lib/ephy-security-levels.c
@@ -52,3 +52,9 @@ ephy_security_level_to_icon_name (EphySecurityLevel level)
return result;
}
+
+gboolean
+ephy_security_level_is_secure (EphySecurityLevel level)
+{
+ return level >= EPHY_SECURITY_LEVEL_STRONG_SECURITY;
+}
diff --git a/lib/ephy-security-levels.h b/lib/ephy-security-levels.h
index ada0d2b..e5e4d14 100644
--- a/lib/ephy-security-levels.h
+++ b/lib/ephy-security-levels.h
@@ -41,4 +41,6 @@ typedef enum
const char *ephy_security_level_to_icon_name (EphySecurityLevel level);
+gboolean ephy_security_level_is_secure (EphySecurityLevel level);
+
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]