polymer-resin intercepts polymer property assignments before they reach XSS-vulnerable sinks like `href="..."` and text nodes in `<script>` elements. This follows the instructions in WORKSPACE for adding a new bower dependency with kaspern's tweak to use the dependency in a rule so that it's found. //lib/js/bower_components.bzl has already been rolled-back per those instructions. The license is the polymer license as can be seen at https://github.com/Polymer/polymer-resin/blob/master/LICENSE though I'm not sure that //tools/js/bower2bazel.py recognizes it as such. Docs for the added component are available at https://github.com/Polymer/polymer-resin/blob/master/README.md https://github.com/Polymer/polymer-resin/blob/master/getting-started.md With this change, when I introduce an XSS vulnerability as below, polymer-resin intercepts and stops it. Patch that introduces a strawman vulnerability. --- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js +++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js @@ -55,6 +55,10 @@ url: '/q/status:abandoned', name: 'Abandoned', }, + { + url: location.hash.replace(/^#/, '') || 'http://example.com/#fragment_echoed_here', + name: 'XSS Me', + }, ], }]; --- Address kaspern's and paladox's comments. --- Undo version bumps for bower dependencies. --- Change Soy index template to parallel app/index.html. --- update polymer-resin to version 1.1.1-beta ---- Load polymer-resin into polygerrit-ui/**/*_test.html After this, I ran the tests with -l chrome -l firefox I ran a handful of tests with -p and observed that the console shows "initResin" is called before test cases start executing. These changes were done programmaticly by running the script below (approximately) thus: ``` gerrit/ $ cd polygerrit-ui/app app/ $ find . -name \*test.html | xargs perl hack-tests.pl ``` ``` use strict; sub removeResin($) { my $s = $_[0]; $s =~ s@<link rel="import" href="[^"]*/polymer-resin/[^"]*"[^>]*>\n?@@; $s =~ s@<script src="[^"]*/polymer-resin/[^"]*"></script>\n?@@; $s =~ s@<script>\s*security\.polymer_resin.*?</script>\n?@@s; return $s; } for my $f (@ARGV) { next if $f =~ m@/bower_components/|/node_modules/@; system('git', 'checkout', $f); print "$f\n"; my @lines = (); open(IN, "<$f") or die "$f: $!"; my $maxLineOfMatch = 0; while (<IN>) { push(@lines, $_); # Put a marker after core loading directives. $maxLineOfMatch = scalar(@lines) if m@/webcomponentsjs/|/polymer[.]html\b|/browser[.]js@; } close(IN) or die "$f: $!"; die "$f missing loading directives" unless $maxLineOfMatch; # Given ./a/b/c/my_test.html, $pathToRoot is "../../.." # assuming no non-leading . or .. components in the path from find. my $pathToRoot = $f; $pathToRoot =~ s@^\.\/@@; $pathToRoot =~ s@^(.*?/)?app/@@; $pathToRoot =~ s@\/[^\/]*$@@; $pathToRoot =~ s@[^/]+@..@g; my $nLines = scalar(@lines); open(OUT, ">$f") or die "$f: $!"; # Output the lines up to the last polymer-resin dependency # loaded explicitly by this test. my $before = join '', @lines[0..($maxLineOfMatch - 1)]; $before = removeResin($before); print OUT "$before"; # Dump out the lines that load polymer-resin and configure it for # polygerrit. if (1) { print OUT qq'<link rel="import" href="$pathToRoot/bower_components/polymer-resin/standalone/polymer-resin-debug.html"/> <script> security.polymer_resin.install({allowedIdentifierPrefixes: [\'\']}); </script> '; } # Emit any remaining lines. my $after = join '', @lines[$maxLineOfMatch..$#lines]; $after = removeResin($after); $after =~ s/^\n*//; print OUT "$after"; close(OUT) or die "$f: $!"; } ``` --- update polymer-resin to version 1.2.1-beta --- update Soy index template to new style polymer-resin initialization ---- fix lint warnings ---- Load test/common-test-setup.html into *_test.html Instead of inserting instructions to load and initialize polymer-resin into every test file, add a common-test-setup.html that does that and also fold iron-test-helpers loading into it. ---- imported files do not need to load webcomponentsjs Change-Id: I71221c36ed8a0fe7f8720c1064a2fcc9555bb8df
45 lines
1.2 KiB
Python
45 lines
1.2 KiB
Python
package(
|
|
default_visibility = ["//visibility:public"],
|
|
)
|
|
|
|
load("//tools/bzl:js.bzl", "bower_component_bundle")
|
|
load("//tools/bzl:genrule2.bzl", "genrule2")
|
|
|
|
bower_component_bundle(
|
|
name = "polygerrit_components.bower_components",
|
|
deps = [
|
|
"//lib/js:es6-promise",
|
|
"//lib/js:fetch",
|
|
# TODO(hanwen): this is inserted separately in the UI zip. Do we need this here?
|
|
"//lib/js:highlightjs",
|
|
"//lib/js:iron-a11y-keys-behavior",
|
|
"//lib/js:iron-autogrow-textarea",
|
|
"//lib/js:iron-dropdown",
|
|
"//lib/js:iron-input",
|
|
"//lib/js:iron-overlay-behavior",
|
|
"//lib/js:iron-selector",
|
|
"//lib/js:moment",
|
|
"//lib/js:page",
|
|
"//lib/js:polymer",
|
|
"//lib/js:polymer-resin",
|
|
"//lib/js:promise-polyfill",
|
|
],
|
|
)
|
|
|
|
genrule2(
|
|
name = "fonts",
|
|
srcs = [
|
|
"//lib/fonts:sourcecodepro",
|
|
],
|
|
outs = ["fonts.zip"],
|
|
cmd = " && ".join([
|
|
"mkdir -p $$TMP/fonts",
|
|
"cp $(SRCS) $$TMP/fonts/",
|
|
"cd $$TMP",
|
|
"find fonts/ -exec touch -t 198001010000 '{}' ';'",
|
|
"zip -qr $$ROOT/$@ fonts",
|
|
]),
|
|
output_to_bindir = 1,
|
|
visibility = ["//visibility:public"],
|
|
)
|