From bbfeb8d220cc67c329aa2b5d6ed693ae1cb54325 Mon Sep 17 00:00:00 2001 From: Jack Westbrook Date: Tue, 4 Mar 2025 11:56:35 +0100 Subject: [PATCH] Feature: Introduce subresource integrity checks (SRI) for frontend assets (#100983) * feat(featuremgmt): introduce feature toggle for enabling sri checks * feat(frontend): use assetSriChecks feature toggle to inject integrity hash into script tags * chore(webpack): align sri algorithms across dev and prod builds * docs(featuremgmt): update assetSriChecks to pass CI * docs(featuremgmt): fix more spelling complaints with assetSriChecks * Add crossorigin attribute * chore(webpack): add subresource-integrity plugin * build(webpack): wrap webpack jsonp loader integrity checks in feature flag checks * revert(index.html): remove crossorigin attribute if assertSriChecks is disabled --------- Co-authored-by: Kristian Bremberg --- .../feature-toggles/index.md | 1 + package.json | 1 + .../src/types/featureToggles.gen.ts | 1 + pkg/services/featuremgmt/codeowners.go | 1 + pkg/services/featuremgmt/registry.go | 7 ++ pkg/services/featuremgmt/toggles_gen.csv | 1 + pkg/services/featuremgmt/toggles_gen.go | 4 ++ pkg/services/featuremgmt/toggles_gen.json | 16 +++++ public/views/index.html | 27 ++++++-- .../plugins/FeatureFlaggedSriPlugin.js | 66 +++++++++++++++++++ scripts/webpack/webpack.dev.js | 1 + scripts/webpack/webpack.prod.js | 8 +++ yarn.lock | 14 ++++ 13 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 scripts/webpack/plugins/FeatureFlaggedSriPlugin.js diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index f40ad6a1766..7ceb0dc3460 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -226,6 +226,7 @@ Experimental features might be changed or removed without prior notice. | `datasourceConnectionsTab` | Shows defined connections for a data source in the plugins detail page | | `newLogsPanel` | Enables the new logs panel in Explore | | `pluginsCDNSyncLoader` | Load plugins from CDN synchronously | +| `assetSriChecks` | Enables SRI checks for Grafana JavaScript assets | ## Development feature toggles diff --git a/package.json b/package.json index 1c9393c4bd9..3708b2b49ac 100644 --- a/package.json +++ b/package.json @@ -248,6 +248,7 @@ "webpack-livereload-plugin": "3.0.2", "webpack-manifest-plugin": "5.0.0", "webpack-merge": "6.0.1", + "webpack-subresource-integrity": "^5.2.0-rc.1", "webpackbar": "^7.0.0", "yaml": "^2.0.0", "yargs": "^17.5.1" diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 87c5ff7c0d1..7e3ac0d6dba 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -254,4 +254,5 @@ export interface FeatureToggles { alertingRuleVersionHistoryRestore?: boolean; newShareReportDrawer?: boolean; rendererDisableAppPluginsPreload?: boolean; + assetSriChecks?: boolean; } diff --git a/pkg/services/featuremgmt/codeowners.go b/pkg/services/featuremgmt/codeowners.go index 13520e2a02b..a201b5e4b23 100644 --- a/pkg/services/featuremgmt/codeowners.go +++ b/pkg/services/featuremgmt/codeowners.go @@ -13,6 +13,7 @@ const ( grafanaBackendServicesSquad codeowner = "@grafana/grafana-backend-services-squad" grafanaSearchAndStorageSquad codeowner = "@grafana/search-and-storage" grafanaPluginsPlatformSquad codeowner = "@grafana/plugins-platform-backend" + grafanaFrontendOpsWG codeowner = "@grafana/frontend-ops" grafanaAsCodeSquad codeowner = "@grafana/grafana-as-code" identityAccessTeam codeowner = "@grafana/identity-access-team" grafanaObservabilityLogsSquad codeowner = "@grafana/observability-logs" diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index f3b1da31b5c..27da9533003 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -1775,6 +1775,13 @@ var ( HideFromDocs: true, FrontendOnly: true, }, + { + Name: "assetSriChecks", + Description: "Enables SRI checks for Grafana JavaScript assets", + Stage: FeatureStageExperimental, + Owner: grafanaFrontendOpsWG, + FrontendOnly: true, + }, } ) diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index fc0b0c8dfb7..ace09d69f56 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -235,3 +235,4 @@ alertingJiraIntegration,experimental,@grafana/alerting-squad,false,false,true alertingRuleVersionHistoryRestore,GA,@grafana/alerting-squad,false,false,true newShareReportDrawer,experimental,@grafana/sharing-squad,false,false,false rendererDisableAppPluginsPreload,experimental,@grafana/sharing-squad,false,false,true +assetSriChecks,experimental,@grafana/frontend-ops,false,false,true diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 56c3a7d53da..d651c7290f6 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -950,4 +950,8 @@ const ( // FlagRendererDisableAppPluginsPreload // Disable pre-loading app plugins when the request is coming from the renderer FlagRendererDisableAppPluginsPreload = "rendererDisableAppPluginsPreload" + + // FlagAssetSriChecks + // Enables SRI checks for Grafana JavaScript assets + FlagAssetSriChecks = "assetSriChecks" ) diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 3f5045123d9..b093cb5dd21 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -598,6 +598,22 @@ "codeowner": "@grafana/grafana-frontend-platform" } }, + { + "metadata": { + "name": "assetSriChecks", + "resourceVersion": "1739984409734", + "creationTimestamp": "2025-02-19T15:56:59Z", + "annotations": { + "grafana.app/updatedTimestamp": "2025-02-19 17:00:09.734088 +0000 UTC" + } + }, + "spec": { + "description": "Enables SRI checks for Grafana JavaScript assets", + "stage": "experimental", + "codeowner": "@grafana/frontend-ops", + "frontend": true + } + }, { "metadata": { "name": "authAPIAccessTokenAuth", diff --git a/public/views/index.html b/public/views/index.html index cd539b05c9e..d7c54f4967b 100644 --- a/public/views/index.html +++ b/public/views/index.html @@ -355,13 +355,26 @@ [[end]] - [[range $asset := .Assets.JSFiles]] - + [[if .Settings.FeatureToggles.assetSriChecks ]] + [[range $asset := .Assets.JSFiles]] + + [[end]] + [[else]] + [[range $asset := .Assets.JSFiles]] + + [[end]] [[end]]