Set 'Secure' cookie flag by default under TLS.

If TLS is enabled and active, Rocket will now set the `Secure` cookie
attribute by default.

Resolves #2425.
This commit is contained in:
Sergio Benitez 2023-04-05 13:04:39 -07:00
parent 89534129de
commit a82508b403
3 changed files with 49 additions and 7 deletions

View File

@ -279,6 +279,8 @@ impl<'a> CookieJar<'a> {
/// * `path`: `"/"`
/// * `SameSite`: `Strict`
///
/// Furthermore, if TLS is enabled, the `Secure` cookie flag is set.
///
/// # Example
///
/// ```rust
@ -298,7 +300,7 @@ impl<'a> CookieJar<'a> {
/// }
/// ```
pub fn add(&self, mut cookie: Cookie<'static>) {
Self::set_defaults(&mut cookie);
Self::set_defaults(self.config, &mut cookie);
self.ops.lock().push(Op::Add(cookie, false));
}
@ -316,8 +318,9 @@ impl<'a> CookieJar<'a> {
/// * `HttpOnly`: `true`
/// * `Expires`: 1 week from now
///
/// These defaults ensure maximum usability and security. For additional
/// security, you may wish to set the `secure` flag.
/// Furthermore, if TLS is enabled, the `Secure` cookie flag is set. These
/// defaults ensure maximum usability and security. For additional security,
/// you may wish to set the `secure` flag.
///
/// # Example
///
@ -333,7 +336,7 @@ impl<'a> CookieJar<'a> {
#[cfg(feature = "secrets")]
#[cfg_attr(nightly, doc(cfg(feature = "secrets")))]
pub fn add_private(&self, mut cookie: Cookie<'static>) {
Self::set_private_defaults(&mut cookie);
Self::set_private_defaults(self.config, &mut cookie);
self.ops.lock().push(Op::Add(cookie, true));
}
@ -473,7 +476,8 @@ impl<'a> CookieJar<'a> {
/// * `path`: `"/"`
/// * `SameSite`: `Strict`
///
fn set_defaults(cookie: &mut Cookie<'static>) {
/// Furthermore, if TLS is enabled, the `Secure` cookie flag is set.
fn set_defaults(config: &Config, cookie: &mut Cookie<'static>) {
if cookie.path().is_none() {
cookie.set_path("/");
}
@ -481,6 +485,10 @@ impl<'a> CookieJar<'a> {
if cookie.same_site().is_none() {
cookie.set_same_site(SameSite::Strict);
}
if cookie.secure().is_none() && config.tls_enabled() {
cookie.set_secure(true);
}
}
/// For each property mentioned below, this method checks if there is a
@ -492,9 +500,10 @@ impl<'a> CookieJar<'a> {
/// * `HttpOnly`: `true`
/// * `Expires`: 1 week from now
///
/// Furthermore, if TLS is enabled, the `Secure` cookie flag is set.
#[cfg(feature = "secrets")]
#[cfg_attr(nightly, doc(cfg(feature = "secrets")))]
fn set_private_defaults(cookie: &mut Cookie<'static>) {
fn set_private_defaults(config: &Config, cookie: &mut Cookie<'static>) {
if cookie.path().is_none() {
cookie.set_path("/");
}
@ -510,6 +519,10 @@ impl<'a> CookieJar<'a> {
if cookie.expires().is_none() {
cookie.set_expires(time::OffsetDateTime::now_utc() + time::Duration::weeks(1));
}
if cookie.secure().is_none() && config.tls_enabled() {
cookie.set_secure(true);
}
}
}

View File

@ -6,4 +6,4 @@ edition = "2021"
publish = false
[dependencies]
rocket = { path = "../../core/lib", features = ["tls", "mtls"] }
rocket = { path = "../../core/lib", features = ["tls", "mtls", "secrets"] }

View File

@ -21,6 +21,35 @@ fn hello_mutual() {
}
}
#[test]
fn secure_cookies() {
use rocket::http::{CookieJar, Cookie};
#[get("/cookie")]
fn cookie(jar: &CookieJar<'_>) {
jar.add(Cookie::new("k1", "v1"));
jar.add_private(Cookie::new("k2", "v2"));
jar.add(Cookie::build("k1u", "v1u").secure(false).finish());
jar.add_private(Cookie::build("k2u", "v2u").secure(false).finish());
}
let client = Client::tracked(super::rocket().mount("/", routes![cookie])).unwrap();
let response = client.get("/cookie").dispatch();
let c1 = response.cookies().get("k1").unwrap();
assert_eq!(c1.secure(), Some(true));
let c2 = response.cookies().get_private("k2").unwrap();
assert_eq!(c2.secure(), Some(true));
let c1 = response.cookies().get("k1u").unwrap();
assert_ne!(c1.secure(), Some(true));
let c2 = response.cookies().get_private("k2u").unwrap();
assert_ne!(c2.secure(), Some(true));
}
#[test]
fn hello_world() {
let profiles = [