Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): allow configuring remote domains with IPC access, closes #5088 #5918

Merged
merged 17 commits into from
Apr 11, 2023

Conversation

lucasfernog
Copy link
Member

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Docs
  • New Binding issue #___
  • Code style update
  • Refactor
  • Build-related changes
  • Other, please describe:

Does this PR introduce a breaking change?

  • Yes, and the changes were approved in issue #___
  • No

Checklist

  • When resolving issues, they are referenced in the PR's title (e.g fix: remove a typo, closes #___, #___)
  • A change file is added if any packages will require a version bump due to this PR per the instructions in the readme.
  • I have added a convincing reason for adding this feature, if necessary

Other information

Copy link

@Sytten Sytten left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking on this challenge. I left some comments, some are blocking IMO.

Apart from those comments, I remember there was a reason why I didnt reuse the same function to inject the scripts in the window, but I don't remember why...

#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ExternalCommandAccessScope {
/// The url to allow, matched against the webview URL using a glob pattern.
pub url: Url,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I used a string here is to allow URL patterns. In our case we need to allow all URLs (*) but there is a more "legitimate" use case to allow all sub domains of a particular domain (*.example.com). Since it is converted into a glob anyway down the line it is fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since in the general use case this is extremely fragile, it should be hard to allow all domains. Non pentest/security apps are the exception with edge cases and deliberately 'insecure' settings.

@@ -2547,6 +2557,37 @@
}
]
},
"ExternalCommandAccessScope": {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsure if the name should change since it also whitelist plugin

/// loaded malicious or compromised sites could start executing commands on the user's device.
///
/// This configuration allows a set of external urls to have access to the Tauri commands.
/// Wildcards patterns are accepted and can be used to allow either all paths or
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK if you use an URL, this is not true anymore. But like I said I prefer the glob.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should still work, we use the same logic for the HTTP allowlist.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will need to test but I am pretty certain the Url parser rejects a single *?

Copy link
Member

@FabianLars FabianLars Dec 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes but you can do https://* (or https://**?) with effectively the same effect.

Edit: stuff like https://*.domain.com also works

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is good for official TaurI, wont cut it for us since we also need to support http but I will maintain my fork.

Copy link
Member

@FabianLars FabianLars Dec 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, you can also do http://... of course. Sure, it's a bit annoying if you want to support both protocols at the same time because it only accepts a single url (especially if we take into account the other convo about finer allowlist-like control)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, thus my recommendation to keep it as a free string

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allowing http is super dangerous. And we could also allow an array of urls on the same scope.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean sure but at the same time this feature is an escape hatch and its made abundantly clear with the name that its dangerous. Http is perfectly acceptable for a lot of use cases like local installations or forwarded via an SSH tunnel.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about only allowing https:// in the normal configuration while you could still manipulate the state (and scope) from rust core if you really really need to and understand the implications?
The same goes for wildcards like https://* and only allow https://example.tld/* or https://*.example.tld this way the already insecure feature is still somewhat reasonable.

invoke.resolver.reject("Scope not defined");
return Ok(());
}

if let Some(module) = &payload.tauri_module {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hummm I don't like that. Currently there is no check for modules like fs. I think we should do something similar to plugin where we can whitelist each module.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about adding an allowlist configuration object for each external access scope, but maybe the root allowlist can be used for that instead? Any reason a Tauri app should have multiple allowlists, one for each URL?

Also this can be confusing since you'd need to enable the allowlist on the root object to add it to the binary, and also allow it in the external access scope.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this is important since it relates to security. Let me give you our usecase.

We have a first in-app window that manages the connections of the user. That window has access to the filesystem to store the configuration.

The user the clicks on a connection which opens a second window with the external URL. We really do not want this window accessing the filesystem directly. We just want it to access certain carefully crafted commands that are safe to call.

This is why I originally only allowed commands and even then I wanted to build a way to limit which commands could be called

Though I agree there could be a default to allow it to take the same values as the general allow list for modules.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think we should add an option to block all Tauri APIs. That's easy and won't bloat the codebase with runtime allowlist checks.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed a change to address this.

invoke.resolver.reject("Plugin not allowed");
return Ok(());
}
}
manager.extend_api(invoke);
} else {
manager.run_invoke_handler(invoke);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we forked Tauri to ship our patched version, I had some ideas. I think whitelisting which command can be run would be really cool, but not a blocker for this PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the message above. Also, it would need a lot of code to add this :(

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can come in a subsequent PR, happy to pitch in for the implementation

@austenc
Copy link

austenc commented Jan 1, 2023

This PR opens up some really cool possibilities. Also, I know it's probably still a WIP.

After trying it out I think that the messaging and/or error related to the windows part of the config can be improved. More specifically, it wasn't clear what value to use for windows -- the app's name (the "title" of the window), or main.

Originally had something like this in my tauri.conf.json:

"dangerousExternalCommandAccess": [
    {
      "url": "https://my-localhost-app-url",
      "windows": ["my-app-name"]
    }
]

When changed to "windows": ["main"] it works.

Not sure whether it's a matter of improving the Scope not defined error message, or whether it's a documentation thing, but that was a tiny papercut I ran into. Thanks again for the work on this!

@lucasfernog
Copy link
Member Author

@austenc we do mention it's the window labels, see https://github.com/tauri-apps/tauri/pull/5918/files#diff-ff73997dde3dc4965aa0c59ce0b37c7d208ae5b6b7686bf19e14d93c98cc1bacR1116. I'll improve the error message though.

@austenc
Copy link

austenc commented Jan 3, 2023

Thanks for helping out a rust noob :) And thanks again for the work on this feature, really great!

@1zun4secondary
Copy link

1zun4secondary commented Jan 14, 2023

How do I exactly use this tauri pull request?
I imported the library into my rust-project via
tauri = { git = "https://github.com/tauri-apps/tauri.git", branch = "feat/remote-ipc", features = ["api-all"] }
which worked out.

But when I run npm run tauri dev, it will say:

Error `tauri.conf.json` error on `tauri > security`: Additional properties are not allowed ('dangerousExternalCommandAccess' was unexpected)

Which makes sense, because the NPM tauri-cli library is still the v1.2.2. I don't know much about NPM, so I was wondering how I can use this pull request now?

@FabianLars
Copy link
Member

@1zun4 see https://tauri.app/v1/guides/faq#how-can-i-use-unpublished-tauri-changes (Using the Tauri CLI from source) - i recommend using the cargo cli instead since it's easier to use a git version imo.

Oh and make sure to also use the tauri-build crate from git.

1zun4secondary pushed a commit to CCBlueX/LiquidLauncher that referenced this pull request Jan 30, 2023
@1zun4secondary
Copy link

1zun4secondary commented Jan 30, 2023

@1zun4 see https://tauri.app/v1/guides/faq#how-can-i-use-unpublished-tauri-changes (Using the Tauri CLI from source) - i recommend using the cargo cli instead since it's easier to use a git version imo.

Oh and make sure to also use the tauri-build crate from git.

Thank you very much! It works flawless with my application. Looking forward for it being merged.

When changed to "windows": ["main"] it works.

Not sure whether it's a matter of improving the Scope not defined error message, or whether it's a documentation thing, but that was a tiny papercut I ran into. Thanks again for the work on this!

... took me a while to figure it out... haha

SenkJu pushed a commit to CCBlueX/LiquidLauncher that referenced this pull request Jan 31, 2023
@ddx95
Copy link

ddx95 commented Mar 8, 2023

Hello, is there any way to modify/add dynamically a value to the dangerousExternalCommandAccess field from the main.rs ? I would need, for example, to get my remote server address from another configuration file, a environment variable or a register key.

@tm1000
Copy link

tm1000 commented Mar 12, 2023

What's the status of this PR?

@prestomation
Copy link

Looks like there is lots of interest in this feature. What can the community to do help it land?

Copy link
Member

@nothingismagick nothingismagick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First of all, this is an approach that removes security features that underly the entire premise of Tauri - all of us can agree on this. It is basically permitting people to drive a motorcycle without a helmet.

To that extent I would propose that we empower the individual to KNOW that this is going on and DENY such permissive use, especially in "*" wildcard situations.

One idea to harden this is to use a model similar to the way our Isolation pattern works, where the app sends an authorization to the remote, and the remote has to reply properly or tauri IPC execution is prevented.

I think @tauri-apps/wg-security must absolutely sign off on this before it enters canon, especially since this modifies the isolation.js guardrails as well.

@lucasfernog
Copy link
Member Author

The security team has been auditing this PR and the finds will be public soon - along with the proposed solution to improve security.

@nothingismagick nothingismagick requested a review from a team March 23, 2023 11:19
@Sytten
Copy link

Sytten commented Mar 23, 2023

Can't wait for their input, I still stand with the review I made 3 months ago. This feature is an escape hatch for "dangerous" usecases, so for me it should allow users to whitelist each element as they wish. It should be very specific in its definition but broad in what it allows (like: I want to allow plugin X for all websites). It should definitely not be used 99% of the time. Our usecase for it was to be able to allow loading remote UI that can interact with some whitelisted tauri commands. It would even be ok with a compiler warning if this feature is used.

@lucasfernog
Copy link
Member Author

One thing I did not touch is usage of remote URLs with the isolation protocol enabled. Since we can't inject the isolation protocol scripts (?) it does not work at all right now.

Copy link
Contributor

@tillmann-crabnebula tillmann-crabnebula left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor documentation changes but implementation looks good to me 👍

core/tauri/src/window.rs Outdated Show resolved Hide resolved
tooling/cli/schema.json Outdated Show resolved Hide resolved
@lucasfernog
Copy link
Member Author

@tillmann-crabnebula I've pushed some changes to make this work with the isolation pattern.

I'm planning on merging this and release 1.3 next week if we can get all blog posts ready.

@lucasfernog lucasfernog changed the title feat(core): allow configuring remote URLs with IPC access, closes #5088 feat(core): allow configuring remote domains with IPC access, closes #5088 Apr 7, 2023
@lucasfernog
Copy link
Member Author

We had to change the approach here from "configuring remote URLs with glob patterns" to "configuring domains" for security reasons. If you need to allow ALL URLs, that is super dangerous and you'll need to do so by listening to the navigation event via WindowBuilder::on_navigation and manually adding the domain to the scope.

core/config-schema/schema.json Outdated Show resolved Hide resolved
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ExternalCommandAccessScope {
/// The url to allow, matched against the webview URL using a glob pattern.
pub url: Url,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since in the general use case this is extremely fragile, it should be hard to allow all domains. Non pentest/security apps are the exception with edge cases and deliberately 'insecure' settings.

core/tauri-utils/src/config.rs Show resolved Hide resolved
/// loaded malicious or compromised sites could start executing commands on the user's device.
///
/// This configuration allows a set of external urls to have access to the Tauri commands.
/// Wildcards patterns are accepted and can be used to allow either all paths or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about only allowing https:// in the normal configuration while you could still manipulate the state (and scope) from rust core if you really really need to and understand the implications?
The same goes for wildcards like https://* and only allow https://example.tld/* or https://*.example.tld this way the already insecure feature is still somewhat reasonable.

@lucasfernog lucasfernog merged commit ee71c31 into dev Apr 11, 2023
@lucasfernog lucasfernog deleted the feat/remote-ipc branch April 11, 2023 11:50
@Sytten
Copy link

Sytten commented Apr 11, 2023

Thats fair, at least there is a way to do it. I will give it a try this week. When is it planned to be released?

@lucasfernog
Copy link
Member Author

We're working to release it this week.

@1zun4secondary
Copy link

huuray

lucasfernog added a commit that referenced this pull request Apr 12, 2023
This was cherry picked from ee71c31, keeping only the logic to block remote URLs from using the IPC.
PR: #5918
lucasfernog added a commit that referenced this pull request Apr 12, 2023
This was cherry picked from ee71c31, keeping only the logic to block remote URLs from using the IPC.
PR: #5918
lucasfernog added a commit that referenced this pull request Apr 12, 2023
This was cherry picked from ee71c31, keeping only the logic to block remote URLs from using the IPC.
PR: #5918
lucasfernog added a commit that referenced this pull request Apr 12, 2023
A regression introduced in the last commit from #5918.
@limitedmage
Copy link

Hello, will this be released for v1.x or will this have to wait until v2.0?

@FabianLars
Copy link
Member

It will be part of v1.3

baiy added a commit to baiy/Ctool that referenced this pull request May 21, 2023
taruri 优先使用 pwa 应用 tauri-apps/tauri#5918
1zun4secondary pushed a commit to CCBlueX/LiquidLauncher that referenced this pull request Jun 3, 2023
Implemented upgrade to Tauri version 1.3, eliminating the need for utilizing the "feat/remote-ipc" branch. Instead, we can now leverage the newly introduced "dangerousRemoteDomainIpcAccess" option in the "tauri.conf.json" file, which was introduced in version 1.3.0. For further details, please refer to the relevant pull request at the following link: tauri-apps/tauri#5918.

While this feature has undergone testing and is confirmed to be functional, it is imperative to conduct further testing to ensure its reliability. If any issues are encountered during usage, kindly report them for further investigation and resolution. Your feedback is greatly appreciated.
@luucasrb
Copy link

luucasrb commented Jun 4, 2023

Can we have this feature in the next branch as a 2.0 feature? I would love to use it in my context, but I cannot downgrade to the 1.x.

@FabianLars
Copy link
Member

@luucasrb It already is in the next branch. iirc it was also part of alpha.9 but not 100% sure about that.

@luucasrb
Copy link

luucasrb commented Jun 8, 2023

Thanks, you are right. My confusion was that the dangerousRemoteDomainIpcAccess config is only in the v1 docs but not in the next docs.

@JVariance
Copy link

We had to change the approach here from "configuring remote URLs with glob patterns" to "configuring domains" for security reasons. If you need to allow ALL URLs, that is super dangerous and you'll need to do so by listening to the navigation event via WindowBuilder::on_navigation and manually adding the domain to the scope.

I want to add domains inside on_navigation, but I just don't succeed. Can you give me an example, how I can do it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.