From 3f97f70b2bf85ee91a73a00435e87c153b6a3feb Mon Sep 17 00:00:00 2001 From: Joffrey Leveugle Date: Mon, 3 May 2021 19:45:52 +0200 Subject: [PATCH] add security warning for anchor element (rel attribute) --- src/compiler/compile/nodes/Element.ts | 20 ++ .../security-anchor-rel-noopener/input.svelte | 34 ++++ .../warnings.json | 182 ++++++++++++++++++ .../input.svelte | 34 ++++ .../warnings.json | 182 ++++++++++++++++++ 5 files changed, 452 insertions(+) create mode 100644 test/validator/samples/security-anchor-rel-noopener/input.svelte create mode 100644 test/validator/samples/security-anchor-rel-noopener/warnings.json create mode 100644 test/validator/samples/security-anchor-rel-noreferrer/input.svelte create mode 100644 test/validator/samples/security-anchor-rel-noreferrer/warnings.json diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index dbde8f1b2d..046d6252f3 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -394,6 +394,26 @@ export default class Element extends Node { const href_attribute = attribute_map.get('href') || attribute_map.get('xlink:href'); const id_attribute = attribute_map.get('id'); const name_attribute = attribute_map.get('name'); + const target_attribute = attribute_map.get('target'); + + if (target_attribute && target_attribute.get_static_value() === '_blank' && href_attribute) { + const href_static_value = href_attribute.get_static_value() ? href_attribute.get_static_value().toLowerCase() : null; + + if (href_static_value === null || href_static_value.startsWith('http') || href_static_value.startsWith('//')) { + const rel = attribute_map.get('rel'); + const rel_values = rel ? rel.get_static_value().split(' ') : []; + const expected_values = ['noopener', 'noreferrer']; + + expected_values.forEach(expected_value => { + if (!rel || rel && rel_values.indexOf(expected_value) < 0) { + component.warn(this, { + code: `security-anchor-rel-${expected_value}`, + message: `Security: Anchor with "target=_blank" should have rel attribute containing the value "${expected_value}"` + }); + } + }); + } + } if (href_attribute) { const href_value = href_attribute.get_static_value(); diff --git a/test/validator/samples/security-anchor-rel-noopener/input.svelte b/test/validator/samples/security-anchor-rel-noopener/input.svelte new file mode 100644 index 0000000000..be146f6676 --- /dev/null +++ b/test/validator/samples/security-anchor-rel-noopener/input.svelte @@ -0,0 +1,34 @@ + +svelte website (invalid) + +svelte website (invalid) +svelte website (invalid) + +svelte website (invalid) + +svelte website (invalid) +svelte website (invalid) + +svelte website (invalid) + +svelte website (invalid) +svelte website (invalid) + +svelte website (invalid) + +svelte website (invalid) +svelte website (invalid) + +Same host (valid) + +Same host (valid) +Same host (valid) + +svelte website (valid) +svelte website (valid) + +svelte website (valid) +svelte website (valid) + +svelte website (valid) +svelte website (valid) \ No newline at end of file diff --git a/test/validator/samples/security-anchor-rel-noopener/warnings.json b/test/validator/samples/security-anchor-rel-noopener/warnings.json new file mode 100644 index 0000000000..6d4c77e7d3 --- /dev/null +++ b/test/validator/samples/security-anchor-rel-noopener/warnings.json @@ -0,0 +1,182 @@ +[ + { + "code": "security-anchor-rel-noopener", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "start": { + "line": 2, + "column": 0, + "character": 54 + }, + "end": { + "line": 2, + "column": 73, + "character": 127 + }, + "pos": 54 + }, + { + "code": "security-anchor-rel-noopener", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "start": { + "line": 4, + "column": 0, + "character": 182 + }, + "end": { + "line": 4, + "column": 80, + "character": 262 + }, + "pos": 182 + }, + { + "code": "security-anchor-rel-noopener", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "start": { + "line": 5, + "column": 0, + "character": 263 + }, + "end": { + "line": 5, + "column": 90, + "character": 353 + }, + "pos": 263 + }, + { + "code": "security-anchor-rel-noopener", + "end": { + "character": 483, + "column": 75, + "line": 7 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "pos": 408, + "start": { + "character": 408, + "column": 0, + "line": 7 + } + }, + { + "code": "security-anchor-rel-noopener", + "end": { + "character": 620, + "column": 82, + "line": 9 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "pos": 538, + "start": { + "character": 538, + "column": 0, + "line": 9 + } + }, + { + "code": "security-anchor-rel-noopener", + "end": { + "character": 713, + "column": 92, + "line": 10 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "pos": 621, + "start": { + "character": 621, + "column": 0, + "line": 10 + } + }, + { + "code": "security-anchor-rel-noopener", + "end": { + "character": 835, + "column": 67, + "line": 12 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "pos": 768, + "start": { + "character": 768, + "column": 0, + "line": 12 + } + }, + { + "code": "security-anchor-rel-noopener", + "end": { + "character": 964, + "column": 74, + "line": 14 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "pos": 890, + "start": { + "character": 890, + "column": 0, + "line": 14 + } + }, + { + "code": "security-anchor-rel-noopener", + "end": { + "character": 1049, + "column": 84, + "line": 15 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "pos": 965, + "start": { + "character": 965, + "column": 0, + "line": 15 + } + }, + { + "code": "security-anchor-rel-noopener", + "end": { + "character": 1176, + "column": 72, + "line": 17 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "pos": 1104, + "start": { + "character": 1104, + "column": 0, + "line": 17 + } + }, + { + "code": "security-anchor-rel-noopener", + "end": { + "character": 1310, + "column": 79, + "line": 19 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "pos": 1231, + "start": { + "character": 1231, + "column": 0, + "line": 19 + } + }, + { + "code": "security-anchor-rel-noopener", + "end": { + "character": 1400, + "column": 89, + "line": 20 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noopener\"", + "pos": 1311, + "start": { + "character": 1311, + "column": 0, + "line": 20 + } + } +] \ No newline at end of file diff --git a/test/validator/samples/security-anchor-rel-noreferrer/input.svelte b/test/validator/samples/security-anchor-rel-noreferrer/input.svelte new file mode 100644 index 0000000000..82248d28ef --- /dev/null +++ b/test/validator/samples/security-anchor-rel-noreferrer/input.svelte @@ -0,0 +1,34 @@ + +svelte website (invalid) + +svelte website (invalid) +svelte website (invalid) + +svelte website (invalid) + +svelte website (invalid) +svelte website (invalid) + +svelte website (invalid) + +svelte website (invalid) +svelte website (invalid) + +svelte website (invalid) + +svelte website (invalid) +svelte website (invalid) + +Same host (valid) + +Same host (valid) +Same host (valid) + +svelte website (valid) +svelte website (valid) + +svelte website (valid) +svelte website (valid) + +svelte website (valid) +svelte website (valid) \ No newline at end of file diff --git a/test/validator/samples/security-anchor-rel-noreferrer/warnings.json b/test/validator/samples/security-anchor-rel-noreferrer/warnings.json new file mode 100644 index 0000000000..5581b3e449 --- /dev/null +++ b/test/validator/samples/security-anchor-rel-noreferrer/warnings.json @@ -0,0 +1,182 @@ +[ + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "start": { + "line": 2, + "column": 0, + "character": 52 + }, + "end": { + "line": 2, + "column": 73, + "character": 125 + }, + "pos": 52 + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "start": { + "line": 4, + "column": 0, + "character": 178 + }, + "end": { + "line": 4, + "column": 80, + "character": 258 + }, + "pos": 178 + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "start": { + "line": 5, + "column": 0, + "character": 259 + }, + "end": { + "line": 5, + "column": 88, + "character": 347 + }, + "pos": 259 + }, + { + "code": "security-anchor-rel-noreferrer", + "end": { + "character": 475, + "column": 75, + "line": 7 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "pos": 400, + "start": { + "character": 400, + "column": 0, + "line": 7 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "end": { + "character": 610, + "column": 82, + "line": 9 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "pos": 528, + "start": { + "character": 528, + "column": 0, + "line": 9 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "end": { + "character": 701, + "column": 90, + "line": 10 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "pos": 611, + "start": { + "character": 611, + "column": 0, + "line": 10 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "end": { + "character": 821, + "column": 67, + "line": 12 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "pos": 754, + "start": { + "character": 754, + "column": 0, + "line": 12 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "end": { + "character": 948, + "column": 74, + "line": 14 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "pos": 874, + "start": { + "character": 874, + "column": 0, + "line": 14 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "end": { + "character": 1031, + "column": 82, + "line": 15 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "pos": 949, + "start": { + "character": 949, + "column": 0, + "line": 15 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "end": { + "character": 1156, + "column": 72, + "line": 17 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "pos": 1084, + "start": { + "character": 1084, + "column": 0, + "line": 17 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "end": { + "character": 1288, + "column": 79, + "line": 19 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "pos": 1209, + "start": { + "character": 1209, + "column": 0, + "line": 19 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "end": { + "character": 1376, + "column": 87, + "line": 20 + }, + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "pos": 1289, + "start": { + "character": 1289, + "column": 0, + "line": 20 + } + } +] \ No newline at end of file