diff --git a/core/includes/common.inc b/core/includes/common.inc
index 4087a42..3b61f25 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -4532,7 +4532,21 @@ function drupal_get_private_key() {
  * @see drupal_get_hash_salt()
  */
 function drupal_get_token($value = '') {
-  return drupal_hmac_base64($value, session_id() . drupal_get_private_key() . drupal_get_hash_salt());
+  // For mixed HTTP(S) sessions, use a constant identifier so that tokens can
+  // be shared between protocols.
+  $identifier = NULL;
+  if ($GLOBALS['is_https'] && settings()->get('mixed_mode_sessions', FALSE)) {
+    $insecure_session_name = substr(session_name(), 1);
+    if (isset($_COOKIE[$insecure_session_name])) {
+      $identifier = $_COOKIE[$insecure_session_name];
+    }
+  }
+  // Otherwise, use the session ID.
+  if (!isset($identifier)) {
+    $identifier = session_id();
+  }
+
+  return drupal_hmac_base64($value, $identifier . drupal_get_private_key() . drupal_get_hash_salt());
 }
 
 /**
diff --git a/core/includes/form.inc b/core/includes/form.inc
index ca9e614..3a5e857 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -1184,6 +1184,11 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
     }
   }
 
+  // Ensure the correct protocol when #https is set.
+  if (!empty($form['#https']) && !$GLOBALS['is_https'] && settings()->get('mixed_mode_sessions', FALSE)) {
+    form_set_error('', t('This form must be submitted over a secure connection.'));
+  }
+
   _form_validate($form, $form_state, $form_id);
   $validated_forms[$form_id] = TRUE;
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Session/SessionHttpsTest.php b/core/modules/system/lib/Drupal/system/Tests/Session/SessionHttpsTest.php
index 787b7d0..16a9061 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Session/SessionHttpsTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Session/SessionHttpsTest.php
@@ -144,13 +144,23 @@ protected function testHttpsSession() {
     $this->drupalGet('user');
     $form = $this->xpath('//form[@id="user-login-form"]');
     $this->assertEqual(substr($form[0]['action'], 0, 6), 'https:', 'Login form action is secure');
-    $form[0]['action'] = $this->httpsUrl('user');
 
+    // Change the form to submit to an insecure URL and make sure the
+    // submission fails.
+    $form[0]['action'] = $this->httpUrl('user');
     $edit = array(
       'name' => $user->name,
       'pass' => $user->pass_raw,
     );
     $this->drupalPost(NULL, $edit, t('Log in'));
+    $this->assertText(t('This form must be submitted over a secure connection.'), 'Form submission failed over HTTP.');
+
+    // Now try with a secure URL and make sure the submission succeeds.
+    $form[0]['action'] = $this->httpsUrl('user');
+    $this->drupalPost(NULL, $edit, t('Log in'));
+    $this->assertNoText(t('This form must be submitted over a secure connection.'), 'Form submission succeeded over HTTPS.');
+    $this->assertLink(t('Log out'), 0, t('User %name successfully logged in.', array('%name' => $user->name)));
+
     // Check secure cookie on secure page.
     $this->assertTrue($this->cookies[$secure_session_name]['secure'], 'The secure cookie has the secure attribute');
     // Check insecure cookie on secure page.
@@ -206,6 +216,19 @@ protected function testHttpsSession() {
     // Test that the user is also authenticated on the insecure site.
     $this->drupalGet("user/{$user->uid}/edit");
     $this->assertResponse(200);
+
+    // Test that tokens can be shared in mixed mode.
+    $this->drupalGet($this->httpUrl('session-test/drupal-token'));
+    $matches = array();
+    preg_match('/\s*drupal_get_token:(.*)\n/', $this->drupalGetContent(), $matches);
+    $this->assertTrue(!empty($matches[1]) , 'Found token on the HTTP URL.');
+    $token_plain = $matches[1];
+    $this->drupalGet($this->httpsUrl('session-test/drupal-token'));
+    $matches = array();
+    preg_match('/\s*drupal_get_token:(.*)\n/', $this->drupalGetContent(), $matches);
+    $this->assertTrue(!empty($matches[1]) , 'Found token on the HTTPS URL.');
+    $token_secure = $matches[1];
+    $this->assertEqual($token_plain, $token_secure, 'Tokens are shared in mixed HTTPS sessions.');
   }
 
   /**
diff --git a/core/modules/system/tests/modules/session_test/session_test.module b/core/modules/system/tests/modules/session_test/session_test.module
index b3e82fd..0d1e4c7 100644
--- a/core/modules/system/tests/modules/session_test/session_test.module
+++ b/core/modules/system/tests/modules/session_test/session_test.module
@@ -22,6 +22,12 @@ function session_test_menu() {
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
   );
+  $items['session-test/drupal-token'] = array(
+    'title' => 'Display a token',
+    'page callback' => '_session_test_drupal_token',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
   $items['session-test/set/%'] = array(
     'title' => 'Set session value',
     'page callback' => '_session_test_set',
@@ -115,6 +121,13 @@ function _session_test_id_from_cookie() {
 }
 
 /**
+ * Menu callback: display the result of drupal_get_token().
+ */
+function _session_test_drupal_token() {
+  return 'drupal_get_token:' . drupal_get_token();
+}
+
+/**
  * Menu callback, sets a message to me displayed on the following page.
  */
 function _session_test_set_message() {
