Add issue for private network request (preflights)

This CL adds an issue indicating that private network requests are going
to require a preflight request in the future.

Bug: chromium:1141824
Change-Id: I7e63872b7612f5a2b6e483a508704f73287c8977
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2848228
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: Lutz Vahl <vahl@chromium.org>
This commit is contained in:
Sigurd Schneider
2021-04-27 12:00:41 +00:00
committed by Commit Bot
parent de7d3fe31c
commit 9149c7abd5
6 changed files with 107 additions and 9 deletions
+2
View File
@@ -222,6 +222,7 @@ all_devtools_files = [
"front_end/models/issues_manager/descriptions/mixedContent.md",
"front_end/models/issues_manager/descriptions/sharedArrayBuffer.md",
"front_end/models/issues_manager/descriptions/corsInsecurePrivateNetwork.md",
"front_end/models/issues_manager/descriptions/corsInsecurePrivateNetworkPreflight.md",
"front_end/models/issues_manager/descriptions/SameSiteExcludeContextDowngradeRead.md",
"front_end/models/issues_manager/descriptions/SameSiteExcludeContextDowngradeSet.md",
"front_end/models/issues_manager/descriptions/SameSiteExcludeNavigationContextDowngrade.md",
@@ -440,6 +441,7 @@ devtools_issue_description_files = [
"corsAllowCredentialsRequired.md",
"corsHeaderDisallowedByPreflightResponse.md",
"corsInsecurePrivateNetwork.md",
"corsInsecurePrivateNetworkPreflight.md",
"corsInvalidHeaderValues.md",
"corsMethodDisallowedByPreflightResponse.md",
"corsOriginMismatch.md",
+1
View File
@@ -243,6 +243,7 @@ grd_files_release_sources = [
"front_end/models/issues_manager/descriptions/corsAllowCredentialsRequired.md",
"front_end/models/issues_manager/descriptions/corsHeaderDisallowedByPreflightResponse.md",
"front_end/models/issues_manager/descriptions/corsInsecurePrivateNetwork.md",
"front_end/models/issues_manager/descriptions/corsInsecurePrivateNetworkPreflight.md",
"front_end/models/issues_manager/descriptions/corsInvalidHeaderValues.md",
"front_end/models/issues_manager/descriptions/corsMethodDisallowedByPreflightResponse.md",
"front_end/models/issues_manager/descriptions/corsOriginMismatch.md",
+16 -8
View File
@@ -26,6 +26,7 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
// eslint-disable-next-line rulesdir/const_enum
export enum IssueCode {
InsecurePrivateNetwork = 'CorsIssue::InsecurePrivateNetwork',
InsecurePrivateNetworkPreflight = 'CorsIssue::InsecurePrivateNetworkPreflight',
InvalidHeaderValues = 'CorsIssue::InvalidHeaders',
WildcardOriginNotAllowed = 'CorsIssue::WildcardOriginWithCredentials',
PreflightResponseInvalid = 'CorsIssue::PreflightResponseInvalid',
@@ -41,8 +42,8 @@ export enum IssueCode {
InvalidResponse = 'CorsIssue::InvalidResponse',
}
export function getIssueCode(corsError: Protocol.Network.CorsError): IssueCode {
switch (corsError) {
function getIssueCode(details: Protocol.Audits.CorsIssueDetails): IssueCode {
switch (details.corsErrorStatus.corsError) {
case Protocol.Network.CorsError.InvalidAllowMethodsPreflightResponse:
case Protocol.Network.CorsError.InvalidAllowHeadersPreflightResponse:
case Protocol.Network.CorsError.PreflightMissingAllowOriginHeader:
@@ -81,7 +82,8 @@ export function getIssueCode(corsError: Protocol.Network.CorsError): IssueCode {
case Protocol.Network.CorsError.InvalidResponse:
return IssueCode.InvalidResponse;
case Protocol.Network.CorsError.InsecurePrivateNetwork:
return IssueCode.InsecurePrivateNetwork;
return details.clientSecurityState?.initiatorIsSecureContext ? IssueCode.InsecurePrivateNetworkPreflight :
IssueCode.InsecurePrivateNetwork;
}
}
@@ -89,7 +91,7 @@ export class CorsIssue extends Issue<IssueCode> {
private issueDetails: Protocol.Audits.CorsIssueDetails;
constructor(issueDetails: Protocol.Audits.CorsIssueDetails, issuesModel: SDK.IssuesModel.IssuesModel) {
super(getIssueCode(issueDetails.corsErrorStatus.corsError), issuesModel);
super(getIssueCode(issueDetails), issuesModel);
this.issueDetails = issueDetails;
}
@@ -102,11 +104,8 @@ export class CorsIssue extends Issue<IssueCode> {
}
getDescription(): MarkdownIssueDescription|null {
switch (getIssueCode(this.issueDetails.corsErrorStatus.corsError)) {
switch (getIssueCode(this.issueDetails)) {
case IssueCode.InsecurePrivateNetwork:
if (this.issueDetails.clientSecurityState?.initiatorIsSecureContext) {
return null;
}
return {
file: 'corsInsecurePrivateNetwork.md',
substitutions: undefined,
@@ -115,6 +114,15 @@ export class CorsIssue extends Issue<IssueCode> {
linkTitle: i18nString(UIStrings.corsForPrivateNetworksRfc),
}],
};
case IssueCode.InsecurePrivateNetworkPreflight:
return {
file: 'corsInsecurePrivateNetworkPreflight.md',
substitutions: undefined,
links: [{
link: 'https://developer.chrome.com/blog/private-network-access-update',
linkTitle: i18nString(UIStrings.corsForPrivateNetworksRfc),
}],
};
case IssueCode.InvalidHeaderValues:
return {
file: 'corsInvalidHeaderValues.md',
@@ -0,0 +1,10 @@
# Ensure private network requests are only made to resources that allow them
A site requested a resource from a network that it could only access because of its users' privileged network position.
These requests expose devices and servers to the internet, increasing the risk of a cross-site request forgery (CSRF) attack, and/or information leakage.
To mitigate these risks, a future version of Chrome will require non-public subresources to opt-into being accessed with a preflight request.
To fix this issue, ensure that response to the [preflight request](issueCorsPreflightRequest) for the private network resource has the `Access-Control-Allow-Private-Network` header set to `true`.
Administrators can make use of the `InsecurePrivateNetworkRequestsAllowed` and `InsecurePrivateNetworkRequestsAllowedForUrls` enterprise policies to temporarily disable this restriction on all or certain websites.
@@ -165,6 +165,7 @@ export class CorsIssueDetailsView extends AffectedResourcesView {
this.appendColumnTitle(header, i18nString(UIStrings.allowCredentialsValueFromHeader));
break;
case IssuesManager.CorsIssue.IssueCode.InsecurePrivateNetwork:
case IssuesManager.CorsIssue.IssueCode.InsecurePrivateNetworkPreflight:
this.appendColumnTitle(header, i18nString(UIStrings.resourceAddressSpace));
this.appendColumnTitle(header, i18nString(UIStrings.initiatorAddressSpace));
this.appendColumnTitle(header, i18nString(UIStrings.initiatorContext));
@@ -293,6 +294,7 @@ export class CorsIssueDetailsView extends AffectedResourcesView {
this.appendIssueDetailCell(element, details.corsErrorStatus.failedParameter, 'code-example');
break;
case IssuesManager.CorsIssue.IssueCode.InsecurePrivateNetwork:
case IssuesManager.CorsIssue.IssueCode.InsecurePrivateNetworkPreflight:
this.appendIssueDetailCell(element, details.resourceIPAddressSpace ?? '');
this.appendIssueDetailCell(element, details.clientSecurityState?.initiatorIPAddressSpace ?? '');
this.appendSecureContextCell(element, details.clientSecurityState?.initiatorIsSecureContext);
@@ -13,7 +13,7 @@ describe('Cors Private Network issue', async () => {
await goToResource('empty.html');
});
it('should display correct information', async () => {
it('should display correct information for insecure contexts', async () => {
await navigateToIssuesTab();
const {frontend} = getBrowserAndPages();
frontend.evaluate(() => {
@@ -86,4 +86,79 @@ describe('Cors Private Network issue', async () => {
'insecure',
]);
});
it('should display correct information for secure contexts', async () => {
await navigateToIssuesTab();
const {frontend} = getBrowserAndPages();
frontend.evaluate(() => {
const issue = {
code: 'CorsIssue',
details: {
corsIssueDetails: {
clientSecurityState: {
initiatorIsSecureContext: true,
initiatorIPAddressSpace: 'Public',
privateNetworkRequestPolicy: 'WarnFromInsecureToMorePrivate',
},
corsErrorStatus: {corsError: 'InsecurePrivateNetwork', failedParameter: ''},
isWarning: true,
request: {requestId: 'request-1', url: 'http://localhost/'},
resourceIPAddressSpace: 'Local',
},
},
};
// @ts-ignore
window.addIssueForTest(issue);
const issue2 = {
code: 'CorsIssue',
details: {
corsIssueDetails: {
clientSecurityState: {
initiatorIsSecureContext: true,
initiatorIPAddressSpace: 'Unknown',
privateNetworkRequestPolicy: 'WarnFromInsecureToMorePrivate',
},
corsErrorStatus: {corsError: 'InsecurePrivateNetwork', failedParameter: ''},
isWarning: true,
request: {requestId: 'request-1', url: 'http://example.com/'},
resourceIPAddressSpace: 'Local',
},
},
};
// @ts-ignore
window.addIssueForTest(issue2);
});
await expandIssue();
const issueElement =
await getIssueByTitle('Ensure private network requests are only made to resources that allow them');
assertNotNull(issueElement);
// TODO(crbug.com/1189877): Remove 2nd space after fixing l10n presubmit check
const section = await getResourcesElement('2 requests', issueElement, '.cors-issue-affected-resource-label');
await ensureResourceSectionIsExpanded(section);
const table = await extractTableFromResourceSection(section.content);
assertNotNull(table);
assert.strictEqual(table.length, 3);
assert.deepEqual(table[0], [
'Request',
'Status',
'Resource Address',
'Initiator Address',
'Initiator Context',
]);
assert.deepEqual(table[1], [
'localhost/',
'warning',
'Local',
'Public',
'secure',
]);
assert.deepEqual(table[2], [
'example.com/',
'warning',
'Local',
'Unknown',
'secure',
]);
});
});