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