Skip to content

Commit f6e32ee

Browse files
authored
feat(core): add dangerous option to disable compile time CSP injection (#3775)
1 parent e05d718 commit f6e32ee

File tree

7 files changed

+113
-167
lines changed

7 files changed

+113
-167
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"tauri": patch
3+
"tauri-codegen": patch
4+
"tauri-utils": patch
5+
---
6+
7+
Added an option to disable the CSP injection of distributable assets nonces and hashes.

core/tauri-codegen/src/context.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ pub struct ContextData {
2727
}
2828

2929
fn load_csp(document: &mut NodeRef, key: &AssetKey, csp_hashes: &mut CspHashes) {
30-
#[cfg(target_os = "linux")]
31-
::tauri_utils::html::inject_csp_token(document);
3230
inject_nonce_token(document);
3331
if let Ok(inline_script_elements) = document.select("script:not(empty)") {
3432
let mut scripts = Vec::new();
@@ -53,22 +51,28 @@ fn map_core_assets(
5351
#[cfg(feature = "isolation")]
5452
let pattern = tauri_utils::html::PatternObject::from(&options.pattern);
5553
let csp = options.csp;
54+
let dangerous_disable_asset_csp_modification = options.dangerous_disable_asset_csp_modification;
5655
move |key, path, input, csp_hashes| {
5756
if path.extension() == Some(OsStr::new("html")) {
5857
let mut document = parse_html(String::from_utf8_lossy(input).into_owned());
5958

6059
if csp {
61-
load_csp(&mut document, key, csp_hashes);
62-
63-
#[cfg(feature = "isolation")]
64-
if let tauri_utils::html::PatternObject::Isolation { .. } = &pattern {
65-
// create the csp for the isolation iframe styling now, to make the runtime less complex
66-
let mut hasher = Sha256::new();
67-
hasher.update(tauri_utils::pattern::isolation::IFRAME_STYLE);
68-
let hash = hasher.finalize();
69-
csp_hashes
70-
.styles
71-
.push(format!("'sha256-{}'", base64::encode(&hash)));
60+
#[cfg(target_os = "linux")]
61+
::tauri_utils::html::inject_csp_token(&mut document);
62+
63+
if !dangerous_disable_asset_csp_modification {
64+
load_csp(&mut document, key, csp_hashes);
65+
66+
#[cfg(feature = "isolation")]
67+
if let tauri_utils::html::PatternObject::Isolation { .. } = &pattern {
68+
// create the csp for the isolation iframe styling now, to make the runtime less complex
69+
let mut hasher = Sha256::new();
70+
hasher.update(tauri_utils::pattern::isolation::IFRAME_STYLE);
71+
let hash = hasher.finalize();
72+
csp_hashes
73+
.styles
74+
.push(format!("'sha256-{}'", base64::encode(&hash)));
75+
}
7276
}
7377
}
7478

@@ -150,7 +154,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
150154
path
151155
)
152156
}
153-
EmbeddedAssets::new(assets_path, map_core_assets(&options))?
157+
EmbeddedAssets::new(assets_path, &options, map_core_assets(&options))?
154158
}
155159
_ => unimplemented!(),
156160
},
@@ -159,6 +163,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
159163
.iter()
160164
.map(|p| config_parent.join(p))
161165
.collect::<Vec<_>>(),
166+
&options,
162167
map_core_assets(&options),
163168
)?,
164169
_ => unimplemented!(),
@@ -295,7 +300,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
295300
}
296301

297302
let key = uuid::Uuid::new_v4().to_string();
298-
let assets = EmbeddedAssets::new(dir.clone(), map_isolation(&options, dir))?;
303+
let assets = EmbeddedAssets::new(dir.clone(), &options, map_isolation(&options, dir))?;
299304
let schema = options.isolation_schema;
300305

301306
quote!(#root::Pattern::Isolation {

core/tauri-codegen/src/embedded_assets.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ struct RawEmbeddedAssets {
9494

9595
impl RawEmbeddedAssets {
9696
/// Creates a new list of (prefix, entry) from a collection of inputs.
97-
fn new(input: EmbeddedAssetsInput) -> Result<Self, EmbeddedAssetsError> {
97+
fn new(input: EmbeddedAssetsInput, options: &AssetOptions) -> Result<Self, EmbeddedAssetsError> {
9898
let mut csp_hashes = CspHashes::default();
9999

100100
input
@@ -123,7 +123,9 @@ impl RawEmbeddedAssets {
123123

124124
// compress all files encountered
125125
Ok(entry) => {
126-
if let Err(error) = csp_hashes.add_if_applicable(&entry) {
126+
if options.dangerous_disable_asset_csp_modification {
127+
Some(Ok((prefix, entry)))
128+
} else if let Err(error) = csp_hashes.add_if_applicable(&entry) {
127129
Some(Err(error))
128130
} else {
129131
Some(Ok((prefix, entry)))
@@ -186,6 +188,7 @@ pub struct AssetOptions {
186188
pub(crate) csp: bool,
187189
pub(crate) pattern: PatternKind,
188190
pub(crate) freeze_prototype: bool,
191+
pub(crate) dangerous_disable_asset_csp_modification: bool,
189192
#[cfg(feature = "isolation")]
190193
pub(crate) isolation_schema: String,
191194
}
@@ -197,12 +200,13 @@ impl AssetOptions {
197200
csp: false,
198201
pattern,
199202
freeze_prototype: false,
203+
dangerous_disable_asset_csp_modification: false,
200204
#[cfg(feature = "isolation")]
201205
isolation_schema: format!("isolation-{}", uuid::Uuid::new_v4()),
202206
}
203207
}
204208

205-
/// Instruct the asset handler to inject the CSP token to HTML files.
209+
/// Instruct the asset handler to inject the CSP token to HTML files (Linux only) and add asset nonces and hashes to the policy.
206210
#[must_use]
207211
pub fn with_csp(mut self) -> Self {
208212
self.csp = true;
@@ -215,6 +219,15 @@ impl AssetOptions {
215219
self.freeze_prototype = freeze;
216220
self
217221
}
222+
223+
/// Instruct the asset handler to **NOT** modify the CSP. This is **NOT** recommended.
224+
pub fn dangerous_disable_asset_csp_modification(
225+
mut self,
226+
dangerous_disable_asset_csp_modification: bool,
227+
) -> Self {
228+
self.dangerous_disable_asset_csp_modification = dangerous_disable_asset_csp_modification;
229+
self
230+
}
218231
}
219232

220233
impl EmbeddedAssets {
@@ -223,10 +236,11 @@ impl EmbeddedAssets {
223236
/// [`Assets`]: tauri_utils::assets::Assets
224237
pub fn new(
225238
input: impl Into<EmbeddedAssetsInput>,
239+
options: &AssetOptions,
226240
map: impl Fn(&AssetKey, &Path, &mut Vec<u8>, &mut CspHashes) -> Result<(), EmbeddedAssetsError>,
227241
) -> Result<Self, EmbeddedAssetsError> {
228242
// we need to pre-compute all files now, so that we can inject data from all files into a few
229-
let RawEmbeddedAssets { paths, csp_hashes } = RawEmbeddedAssets::new(input.into())?;
243+
let RawEmbeddedAssets { paths, csp_hashes } = RawEmbeddedAssets::new(input.into(), options)?;
230244

231245
struct CompressState {
232246
csp_hashes: CspHashes,

core/tauri-utils/src/config.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,16 @@ pub struct SecurityConfig {
781781
/// Freeze the `Object.prototype` when using the custom protocol.
782782
#[serde(default)]
783783
pub freeze_prototype: bool,
784+
/// Disables the Tauri-injected CSP sources.
785+
///
786+
/// At compile time, Tauri parses all the frontend assets and changes the Content-Security-Policy
787+
/// to only allow loading of your own scripts and styles by injecting nonce and hash sources.
788+
/// This stricts your CSP, which may introduce issues when using along with other flexing sources.
789+
///
790+
/// **WARNING:** Only disable this if you know what you are doing and have properly configured the CSP.
791+
/// Your application might be vulnerable to XSS attacks without this Tauri protection.
792+
#[serde(default)]
793+
pub dangerous_disable_asset_csp_modification: bool,
784794
}
785795

786796
/// Defines an allowlist type.
@@ -2623,8 +2633,16 @@ mod build {
26232633
let csp = opt_lit(self.csp.as_ref());
26242634
let dev_csp = opt_lit(self.dev_csp.as_ref());
26252635
let freeze_prototype = self.freeze_prototype;
2636+
let dangerous_disable_asset_csp_modification = self.dangerous_disable_asset_csp_modification;
26262637

2627-
literal_struct!(tokens, SecurityConfig, csp, dev_csp, freeze_prototype);
2638+
literal_struct!(
2639+
tokens,
2640+
SecurityConfig,
2641+
csp,
2642+
dev_csp,
2643+
freeze_prototype,
2644+
dangerous_disable_asset_csp_modification
2645+
);
26282646
}
26292647
}
26302648

@@ -2874,6 +2892,7 @@ mod test {
28742892
csp: None,
28752893
dev_csp: None,
28762894
freeze_prototype: false,
2895+
dangerous_disable_asset_csp_modification: false,
28772896
},
28782897
allowlist: AllowlistConfig::default(),
28792898
system_tray: None,

0 commit comments

Comments
 (0)