-
Notifications
You must be signed in to change notification settings - Fork 896
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
[iOS] - Add CSPs support in Chromium WebUI #26402
base: master
Are you sure you want to change the base?
Conversation
The security team is monitoring all repositories for certain keywords. This PR includes the word(s) "csp" and so security team members have been added as reviewers to take a look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Brandon-T do we expose any mojo interfaces to chrome-untrusted? For example, does MojoJS get injected in these contexts? I believe @bridiver mentioned that the last time we tried to implement it, page permissions weren't too much different from chrome:// urls
chromium-untrusted must have access to mojom APIs. It's not injected by default but if we created an untrusted html page that loads the mojom script, it will work. If an untrusted page programmatically loads the script, it'll work. mojom bindings are available to chromium-untrusted as they're supposed to be afaik. I can probably block them, but how would it communicate with native code? We would have to disable it via: https://source.chromium.org/chromium/chromium/src/+/main:ios/web/web_state/ui/crw_wk_ui_handler.mm;l=256;drc=a2ed1bfa50bdef7869f102cb1436f0c95cca812f;bpv=0;bpt=1 But https://chromium.googlesource.com/chromium/src/+/main/docs/chrome_untrusted.md states:
But iOS doesn't have a |
This document
So I guess the question is, can chrome-untrusted on iOS bind to any interface or is it limited in the same way as on desktop. |
I believe an untrusted frame would be able to access whatever interfaces are bound to the main-frame. is called no matter which frame or scheme calls it. So:
From the or a RenderHost frame. Chrome iOS doesn't have a registry to register any WebUI, whereas Desktop registers every WebUI regardless of if it's trusted or not. Chrome's regular ones are registered here: https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/chrome_browser_interface_binders.cc;l=768;drc=7fb345a0da63049b102e1c0bcdc8d7831110e324;bpv=0;bpt=1 I'm not sure if it's even possible to replicate that behaviour and fix it on iOS.
Already doesn't apply to iOS. We would have to figure out a way to do all of that for both trusted and untrusted if we want this to follow Desktop or this doc. |
This unfortunately defeats the purpose of chrome-untrusted. I think we should decouple CSP logic (which lgtm) from this PR and figure out how to make chrome-untrusted secure. |
f207166
to
e8024f1
Compare
The security team is monitoring all repositories for certain keywords. This PR includes the word(s) "policy, csp" and so security team members have been added as reviewers to take a look. |
9075cd7
to
c8f38a6
Compare
Only |
\ | ||
public: \ | ||
const network::mojom::URLResponseHeadPtr getResponse() { \ | ||
return response_.Clone(); \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
they completely ignore the headers from the response (and they use *
for the Access-Control-Allow-Origin
header. They hardcode headers). So to add the actual response headers, I need to retrieve it, and add it here (in this PR):
brave-core/chromium_src/ios/web/webui/crw_web_ui_scheme_handler.mm
Lines 64 to 77 in c8f38a6
const network::mojom::URLResponseHeadPtr responseHead = | |
fetcher->getResponse(); | |
if (responseHead) { | |
const scoped_refptr<net::HttpResponseHeaders> headers = | |
responseHead->headers; | |
if (headers) { | |
// const std::string& raw_headers = headers->raw_headers(); | |
NSMutableDictionary* responseHeaders = | |
[strongSelf parseHeaders:headers]; | |
if (![responseHeaders objectForKey:@"Content-Type"]) { | |
[responseHeaders setObject:mimeType forKey:@"Content-Type"]; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you please add comments explaining?
GetFinalURL(); \ | ||
} \ | ||
\ | ||
response_ = url_loader_->TakeResponseInfo(); \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above, what is this for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's an override for: https://source.chromium.org/chromium/chromium/src/+/main:ios/web/webui/url_fetcher_block_adapter.mm;l=43;bpv=0;bpt=1
So that I can retrieve the response that contains the headers, so that I can give them to WebKit's WKURLSchemeHandler here:
fetcher->getResponse(); |
and pass them to WebKit. It's used in the files linked above, as part of this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above, please add comments
|
||
#include <cstdint> | ||
|
||
namespace network::mojom { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't forward declare enums
virtual std::string GetContentSecurityPolicy( \ | ||
network::mojom::CSPDirectiveName directive) const; \ | ||
\ | ||
private: \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the purpose of this?
} | ||
|
||
bool URLDataSourceIOS::ShouldServiceRequest(const GURL& url) const { | ||
return URLDataSourceIOS::ShouldServiceRequest_ChromiumImpl(url); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't this also need to include kChromeUIUntrustedScheme
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if it doesn't then overriding this is pointless
} // namespace | ||
|
||
namespace web { | ||
bool URLDataSourceIOS::ShouldAddContentSecurityPolicy() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adding this seems pointless if it's always going to return true
#define ShouldDenyXFrameOptions ShouldDenyXFrameOptions()); \ | ||
job->set_add_content_security_policy( \ | ||
source->source()->ShouldAddContentSecurityPolicy()); \ | ||
job->set_content_security_policy_object_source( \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is already called in URLDataManagerIOSBackend::StartRequest
, why are we calling it again?
c8f38a6
to
762e56e
Compare
85e7120
to
014a4ae
Compare
import("//build/config/features.gni") | ||
import("//mojo/public/tools/bindings/mojom.gni") | ||
|
||
source_set("public") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public
doesn't make sense inside ios/browser
, this is more equivalent to URLDataSourceIOSImpl
because it's a brave specific implementation.
std::move(callback).Run(response); | ||
} | ||
|
||
std::string BraveWebUIIOSDataSource::GetMimeType( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why aren't we subclassing WebUIIOSDataSourceImpl
to get this stuff? We don't want to duplicate it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it isn't public, but per dm I think we can have BraveWebUIIOSDataSource
own an instance of WebUIIOSDataSourceImpl
that is created through WebUIIOSDataSource::Create
and then proxy these methods to it
9514589
to
1a1a6d5
Compare
a5b8533
to
6ff07ce
Compare
6ff07ce
to
f56d5f0
Compare
[puLL-Merge] - brave/brave-core@26402 DescriptionThis PR introduces significant changes to the Brave iOS browser, primarily focusing on enhancing WebUI functionality and security. It adds support for the Possible Issues
Security Hotspots
ChangesChanges
sequenceDiagram
participant WebUI
participant BraveWebUIIOSDataSource
participant BraveURLDataSourceIOS
participant WebClient
WebUI->>BraveWebUIIOSDataSource: Request data
BraveWebUIIOSDataSource->>BraveURLDataSourceIOS: Get content
BraveURLDataSourceIOS->>WebClient: Get resource
WebClient-->>BraveURLDataSourceIOS: Return resource
BraveURLDataSourceIOS->>BraveURLDataSourceIOS: Apply CSP
BraveURLDataSourceIOS-->>BraveWebUIIOSDataSource: Return content
BraveWebUIIOSDataSource-->>WebUI: Serve content
|
742e538
to
3e2cb38
Compare
3e2cb38
to
31db77d
Compare
Security Review
Summary
Content-Security-Policy
and other headers to be set on WebUI responses so that WebKit can enforce such policies. See screenshots below.Resolves brave/brave-browser#42138
Submitter Checklist:
QA/Yes
orQA/No
;release-notes/include
orrelease-notes/exclude
;OS/...
) to the associated issuenpm run test -- brave_browser_tests
,npm run test -- brave_unit_tests
wikinpm run presubmit
wiki,npm run gn_check
,npm run tslint
git rebase master
(if needed)Reviewer Checklist:
gn
After-merge Checklist:
changes has landed on
Screenshots:
Testing Overrides by adding
script-src
with anonce
:WebKit sees the above
nonce
:Testing Default CSPs (no overrides):
Without this PR (Current AppStore Build - Same as Chrome-iOS):
The above matches Desktop: