@@ -37,6 +37,7 @@ fn post_upgrade(args: InternetIdentityFrontendArgs) {
3737
3838fn certify_all_assets ( args : InternetIdentityFrontendArgs ) {
3939 let static_assets = get_static_assets ( & args) ;
40+ let related_origins = args. related_origins . as_ref ( ) ;
4041
4142 // 2. Extract integrity hashes for inline scripts from HTML files
4243 let integrity_hashes = static_assets
@@ -82,6 +83,7 @@ fn certify_all_assets(args: InternetIdentityFrontendArgs) {
8283 content_type : Some ( "text/html" . to_string ( ) ) ,
8384 headers : get_asset_headers (
8485 integrity_hashes. clone ( ) ,
86+ related_origins,
8587 vec ! [ (
8688 "cache-control" . to_string( ) ,
8789 NO_CACHE_ASSET_CACHE_CONTROL . to_string( ) ,
@@ -115,7 +117,11 @@ fn certify_all_assets(args: InternetIdentityFrontendArgs) {
115117 path,
116118 content_type : Some ( content_type. to_mime_type_string ( ) ) ,
117119 encodings,
118- headers : get_asset_headers ( integrity_hashes. clone ( ) , vec ! [ headers] ) ,
120+ headers : get_asset_headers (
121+ integrity_hashes. clone ( ) ,
122+ related_origins,
123+ vec ! [ headers] ,
124+ ) ,
119125 fallback_for : vec ! [ ] ,
120126 aliased_by : vec ! [ ] ,
121127 }
@@ -137,8 +143,23 @@ fn certify_all_assets(args: InternetIdentityFrontendArgs) {
137143
138144fn get_asset_headers (
139145 integrity_hashes : Vec < String > ,
146+ related_origins : Option < & Vec < String > > ,
140147 additional_headers : Vec < HeaderField > ,
141148) -> Vec < HeaderField > {
149+ let credentials_allowlist = if let Some ( related_origins) = related_origins {
150+ if related_origins. is_empty ( ) {
151+ "self" . to_string ( )
152+ } else {
153+ let quoted: Vec < String > = related_origins
154+ . iter ( )
155+ . map ( |origin| format ! ( "\" {origin}\" " ) )
156+ . collect ( ) ;
157+ format ! ( "self {}" , quoted. join( " " ) )
158+ }
159+ } else {
160+ "self" . to_string ( )
161+ } ;
162+
142163 // List of recommended security headers as per https://owasp.org/www-project-secure-headers/
143164 // These headers enable browser security features (like limit access to platform apis and set
144165 // iFrame policies, etc.)
@@ -155,7 +176,7 @@ fn get_asset_headers(
155176 // Comprehensive policy to prevent XSS attacks and data injection
156177 (
157178 "Content-Security-Policy" . to_string( ) ,
158- get_content_security_policy( integrity_hashes) ,
179+ get_content_security_policy( integrity_hashes, related_origins ) ,
159180 ) ,
160181 // Strict-Transport-Security (HSTS)
161182 // Forces browsers to use HTTPS for all future requests to this domain
@@ -178,7 +199,8 @@ fn get_asset_headers(
178199 // - sync-xhr=(self): Allow synchronous XMLHttpRequest from same origin
179200 (
180201 "Permissions-Policy" . to_string( ) ,
181- "accelerometer=(),\
202+ format!(
203+ "accelerometer=(),\
182204 autoplay=(),\
183205 camera=(),\
184206 clipboard-read=(),\
@@ -197,14 +219,14 @@ fn get_asset_headers(
197219 midi=(),\
198220 payment=(),\
199221 picture-in-picture=(),\
200- publickey-credentials-get=(self ),\
222+ publickey-credentials-get=({credentials_allowlist} ),\
201223 screen-wake-lock=(),\
202224 serial=(),\
203225 sync-xhr=(self),\
204226 usb=(),\
205227 web-share=(),\
206228 xr-spatial-tracking=()"
207- . to_string ( ) ,
229+ ) ,
208230 ) ,
209231 ] ;
210232 headers. extend ( additional_headers) ;
@@ -246,12 +268,18 @@ fn get_asset_headers(
246268/// font-src 'self':
247269/// Allow fonts only from same origin
248270///
249- /// frame-ancestors 'self':
250- /// Control embedding - only allow same origin
271+ /// frame-ancestors 'self' <related_origins...>:
272+ /// Control embedding - allow same origin and configured related origins
273+ ///
274+ /// frame-src 'self' <related_origins...>:
275+ /// Allow framing only from same origin and configured related origins
251276///
252277/// upgrade-insecure-requests (production only):
253278/// Automatically upgrade HTTP requests to HTTPS (omitted in dev for localhost)
254- fn get_content_security_policy ( integrity_hashes : Vec < String > ) -> String {
279+ fn get_content_security_policy (
280+ integrity_hashes : Vec < String > ,
281+ related_origins : Option < & Vec < String > > ,
282+ ) -> String {
255283 let connect_src = "'self' https:" ;
256284
257285 // Allow connecting via http for development purposes
@@ -272,6 +300,16 @@ fn get_content_security_policy(integrity_hashes: Vec<String>) -> String {
272300 )
273301 } ;
274302
303+ let embedding_allowlist = if let Some ( related_origins) = related_origins {
304+ if related_origins. is_empty ( ) {
305+ "'self'" . to_string ( )
306+ } else {
307+ format ! ( "'self' {}" , related_origins. join( " " ) )
308+ }
309+ } else {
310+ "'self'" . to_string ( )
311+ } ;
312+
275313 let csp = format ! (
276314 "default-src 'none';\
277315 connect-src {connect_src};\
@@ -282,8 +320,8 @@ fn get_content_security_policy(integrity_hashes: Vec<String>) -> String {
282320 style-src 'self' 'unsafe-inline';\
283321 style-src-elem 'self' 'unsafe-inline';\
284322 font-src 'self';\
285- frame-ancestors 'self' ;\
286- frame-src 'self' ;"
323+ frame-ancestors {embedding_allowlist} ;\
324+ frame-src {embedding_allowlist} ;"
287325 ) ;
288326
289327 // For production builds, upgrade all HTTP connections to HTTPS
0 commit comments