fix: SameSite=Strict → Lax for session cookies (fixes iframe fetch)
SameSite=Strict prevents cookies from being sent when iframe content (like the LND UI at /app/lnd/) fetches endpoints on the parent origin (/lnd-connect-info). Lax still protects against CSRF on POST requests but allows same-site GET navigations and fetches from iframes. This was the root cause of "Failed to fetch" on LND Connect. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -117,6 +117,8 @@ const UNAUTHENTICATED_METHODS: &[&str] = &[
|
||||
"federation.peer-joined",
|
||||
"federation.peer-address-changed",
|
||||
"federation.get-state",
|
||||
// Fleet telemetry ingest: called by remote nodes posting reports
|
||||
"telemetry.ingest",
|
||||
];
|
||||
|
||||
/// Simple TTL cache for read-only RPC responses.
|
||||
@@ -704,6 +706,10 @@ impl RpcHandler {
|
||||
"analytics.disable" => self.handle_analytics_disable().await,
|
||||
"analytics.get-snapshot" => self.handle_analytics_get_snapshot().await,
|
||||
"telemetry.report" => self.handle_telemetry_report().await,
|
||||
"telemetry.ingest" => self.handle_telemetry_ingest(params).await,
|
||||
"telemetry.fleet-status" => self.handle_telemetry_fleet_status().await,
|
||||
"telemetry.fleet-node-history" => self.handle_telemetry_fleet_node_history(params).await,
|
||||
"telemetry.fleet-alerts" => self.handle_telemetry_fleet_alerts().await,
|
||||
|
||||
// Real-time metrics monitoring
|
||||
"monitoring.current" => self.handle_monitoring_current().await,
|
||||
@@ -846,13 +852,13 @@ impl RpcHandler {
|
||||
let csrf_token = derive_csrf_token(&token);
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!("session={}; HttpOnly; SameSite=Strict; Path=/{}", token, self.cookie_suffix())
|
||||
format!("session={}; HttpOnly; SameSite=Lax; Path=/{}", token, self.cookie_suffix())
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!("csrf_token={}; SameSite=Strict; Path=/{}", csrf_token, self.cookie_suffix())
|
||||
format!("csrf_token={}; SameSite=Lax; Path=/{}", csrf_token, self.cookie_suffix())
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
@@ -873,20 +879,20 @@ impl RpcHandler {
|
||||
let remember_token = self.session_store.create_remember_token();
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!("session={}; HttpOnly; SameSite=Strict; Path=/{}", token, self.cookie_suffix())
|
||||
format!("session={}; HttpOnly; SameSite=Lax; Path=/{}", token, self.cookie_suffix())
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!("csrf_token={}; SameSite=Strict; Path=/{}", csrf_token, self.cookie_suffix())
|
||||
format!("csrf_token={}; SameSite=Lax; Path=/{}", csrf_token, self.cookie_suffix())
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
// Remember-me: HMAC-signed, survives backend restarts (30-day TTL)
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!("remember={}; HttpOnly; SameSite=Strict; Path=/; Max-Age={}{}", remember_token, REMEMBER_TTL, self.cookie_suffix())
|
||||
format!("remember={}; HttpOnly; SameSite=Lax; Path=/; Max-Age={}{}", remember_token, REMEMBER_TTL, self.cookie_suffix())
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
@@ -911,7 +917,7 @@ impl RpcHandler {
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!(
|
||||
"session={}; HttpOnly; SameSite=Strict; Path=/{}",
|
||||
"session={}; HttpOnly; SameSite=Lax; Path=/{}",
|
||||
new_token,
|
||||
self.cookie_suffix()
|
||||
)
|
||||
@@ -921,7 +927,7 @@ impl RpcHandler {
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!(
|
||||
"csrf_token={}; SameSite=Strict; Path=/{}",
|
||||
"csrf_token={}; SameSite=Lax; Path=/{}",
|
||||
csrf_token,
|
||||
self.cookie_suffix()
|
||||
)
|
||||
@@ -931,7 +937,7 @@ impl RpcHandler {
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!(
|
||||
"remember={}; HttpOnly; SameSite=Strict; Path=/; Max-Age={}{}",
|
||||
"remember={}; HttpOnly; SameSite=Lax; Path=/; Max-Age={}{}",
|
||||
remember_token,
|
||||
REMEMBER_TTL,
|
||||
self.cookie_suffix()
|
||||
@@ -958,7 +964,7 @@ impl RpcHandler {
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!(
|
||||
"session={}; HttpOnly; SameSite=Strict; Path=/{}",
|
||||
"session={}; HttpOnly; SameSite=Lax; Path=/{}",
|
||||
new_token,
|
||||
self.cookie_suffix()
|
||||
)
|
||||
@@ -968,7 +974,7 @@ impl RpcHandler {
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!(
|
||||
"csrf_token={}; SameSite=Strict; Path=/{}",
|
||||
"csrf_token={}; SameSite=Lax; Path=/{}",
|
||||
csrf_token,
|
||||
self.cookie_suffix()
|
||||
)
|
||||
@@ -986,13 +992,13 @@ impl RpcHandler {
|
||||
let secure_suffix = if self.config.dev_mode { "" } else { "; Secure" };
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!("session=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0{}", secure_suffix)
|
||||
format!("session=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0{}", secure_suffix)
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!("csrf_token=; SameSite=Strict; Path=/; Max-Age=0{}", secure_suffix)
|
||||
format!("csrf_token=; SameSite=Lax; Path=/; Max-Age=0{}", secure_suffix)
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
@@ -1003,13 +1009,13 @@ impl RpcHandler {
|
||||
let suffix = self.cookie_suffix();
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!("session={}; HttpOnly; SameSite=Strict; Path=/{}", new_session, suffix)
|
||||
format!("session={}; HttpOnly; SameSite=Lax; Path=/{}", new_session, suffix)
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
response.headers_mut().append(
|
||||
"Set-Cookie",
|
||||
format!("csrf_token={}; SameSite=Strict; Path=/{}", new_csrf, suffix)
|
||||
format!("csrf_token={}; SameSite=Lax; Path=/{}", new_csrf, suffix)
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user