diff --git a/core/includes/common.inc b/core/includes/common.inc
index 44fa367..7f1d592 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -4862,7 +4862,14 @@ function drupal_get_private_key() {
  *   An additional value to base the token on.
  */
 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.
+  if (variable_get('https', FALSE) && $GLOBALS['is_https'] && isset($_COOKIE[substr(session_name(), 1)])) {
+    $session_id = $_COOKIE[substr(session_name(), 1)];
+  }
+  else {
+    $session_id = session_id();
+  }
+  return drupal_hmac_base64($value, $session_id . drupal_get_private_key() . drupal_get_hash_salt());
 }
 
 /**
diff --git a/core/includes/form.inc b/core/includes/form.inc
index a142e69..6c01784 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -1151,6 +1151,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']) {
+    form_set_error('', t('This form requires HTTPS.  Contact the site administrator if the problem persists.'));
+  }
+
   _form_validate($form, $form_state, $form_id);
   $validated_forms[$form_id] = TRUE;
 
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 25139e6..f3a4966 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -2821,4 +2821,32 @@ abstract class WebTestBase extends TestBase {
       $this->verbose(t('Email:') . '<pre>' . print_r($mail, TRUE) . '</pre>');
     }
   }
+
+  /**
+   * Builds a URL for submitting a mock HTTPS request to HTTP test environments.
+   *
+   * @param $url
+   *   A Drupal path such as 'user'.
+   *
+   * @return
+   *   An absolute URL.
+   */
+  protected function httpsUrl($url) {
+    global $base_url;
+    return $base_url . '/modules/simpletest/tests/https.php?q=' . $url;
+  }
+
+  /**
+   * Builds a URL for submitting a mock HTTP request to HTTPS test environments.
+   *
+   * @param $url
+   *   A Drupal path such as 'user'.
+   *
+   * @return
+   *   An absolute URL.
+   */
+  protected function httpUrl($url) {
+    global $base_url;
+    return $base_url . '/modules/simpletest/tests/http.php?q=' . $url;
+  }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/FormHttpsOnlyTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/FormHttpsOnlyTest.php
new file mode 100644
index 0000000..83d3102
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Form/FormHttpsOnlyTest.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Form\FormHttpsOnlyTest.
+ */
+
+namespace Drupal\system\Tests\Form;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests #https property.
+ */
+class FormHttpsOnlyTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('form_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Form HTTPS only',
+      'description' => 'Tests form API handling of #https.',
+      'group' => 'Form API',
+    );
+  }
+
+  function testHttpsOnly() {
+    $path = 'form-test/https-only';
+    $edit = array('textfield' => '123');
+    $submit = t('Submit');
+
+    $this->drupalGet($path);
+    $form = $this->xpath('//form[@id="form-test-https-only"]');
+    $form[0]['action'] = $this->httpsUrl($path);
+    $this->drupalPost(NULL, $edit, $submit);
+    $this->assertText(t('The form has been successfully submitted.'), t('Form submission succeeded over HTTPS.'));
+
+    $this->drupalGet($path);
+    $form = $this->xpath('//form[@id="form-test-https-only"]');
+    $form[0]['action'] = $this->httpUrl($path);
+    $this->drupalPost(NULL, $edit, $submit);
+    $this->assertText(t('This form requires HTTPS. Contact the site administrator if the problem persists.'), t('Form submission failed over HTTP.'));
+  }
+}
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 c8e6703..4c70f36 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Session/SessionHttpsTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Session/SessionHttpsTest.php
@@ -223,32 +223,4 @@ class SessionHttpsTest extends WebTestBase {
     );
     return $this->assertTrue(db_query('SELECT timestamp FROM {sessions} WHERE sid = :sid AND ssid = :ssid', $args)->fetchField(), $assertion_text);
   }
-
-  /**
-   * Builds a URL for submitting a mock HTTPS request to HTTP test environments.
-   *
-   * @param $url
-   *   A Drupal path such as 'user'.
-   *
-   * @return
-   *   An absolute URL.
-   */
-  protected function httpsUrl($url) {
-    global $base_url;
-    return $base_url . '/core/modules/system/tests/https.php/' . $url;
-  }
-
-  /**
-   * Builds a URL for submitting a mock HTTP request to HTTPS test environments.
-   *
-   * @param $url
-   *   A Drupal path such as 'user'.
-   *
-   * @return
-   *   An absolute URL.
-   */
-  protected function httpUrl($url) {
-    global $base_url;
-    return $base_url . '/core/modules/system/tests/http.php/' . $url;
-  }
 }
diff --git a/core/modules/system/tests/modules/form_test/form_test.module b/core/modules/system/tests/modules/form_test/form_test.module
index 45b3cba..1bf6bf8 100644
--- a/core/modules/system/tests/modules/form_test/form_test.module
+++ b/core/modules/system/tests/modules/form_test/form_test.module
@@ -209,6 +209,13 @@ function form_test_menu() {
     'access callback' => TRUE,
     'type' => MENU_CALLBACK,
   );
+  $items['form-test/https-only'] = array(
+    'title' => 'FAPI test for mixed-mode sessions',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_test_https_only'),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
 
   $items['form-test/form-rebuild-preserve-values'] = array(
     'title' => 'Form values preservation during rebuild test',
@@ -2284,3 +2291,29 @@ function form_test_html_id($form, &$form_state) {
   );
   return $form;
 }
+
+/**
+ * Provides a page callback and form to test the form #https-attribute.
+ *
+ * @see Drupal\system\Tests\Form\FormHttpsOnlyTest
+ */
+function form_test_https_only($form, &$form_state) {
+  $form['textfield'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Textfield'),
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Submit'),
+  );
+  $form['#https'] = TRUE;
+  return $form;
+}
+
+/**
+ * Submit handler for the #https-test form.
+ */
+function form_test_https_only_submit($form, &$form_state) {
+  drupal_set_message('The form has been successfully submitted.');
+  $form_state['redirect'] = FALSE;
+}
