From c7c6c05c7f891a864f888f14b5770c467970feac Mon Sep 17 00:00:00 2001 From: Joffrey LEVEUGLE Date: Thu, 13 Oct 2022 15:58:10 +0200 Subject: [PATCH] [feat] add security warning for anchor element (rel attribute) (#6289) * add security warning for anchor element (rel attribute) * manage more case for security warnings on anchor (aplocks, false positive ...) * remove noopener checks as noreferrer imples noopener Co-authored-by: tanhauhau --- src/compiler/compile/nodes/Element.ts | 20 ++ .../input.svelte | 31 ++ .../warnings.json | 272 ++++++++++++++++++ 3 files changed, 323 insertions(+) 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 d5fad18f54..298276c437 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -613,6 +613,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.match(/^(https?:)?\/\//i)) { + const rel = attribute_map.get('rel'); + const rel_values = rel ? rel.get_static_value().split(' ') : []; + const expected_values = ['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-noreferrer/input.svelte b/test/validator/samples/security-anchor-rel-noreferrer/input.svelte new file mode 100644 index 0000000000..de52d5a596 --- /dev/null +++ b/test/validator/samples/security-anchor-rel-noreferrer/input.svelte @@ -0,0 +1,31 @@ +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) +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) +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..24c10fb763 --- /dev/null +++ b/test/validator/samples/security-anchor-rel-noreferrer/warnings.json @@ -0,0 +1,272 @@ +[ + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 73, + "column": 73, + "line": 1 + }, + "pos": 0, + "start": { + "character": 0, + "column": 0, + "line": 1 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 154, + "column": 80, + "line": 2 + }, + "pos": 74, + "start": { + "character": 74, + "column": 0, + "line": 2 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 243, + "column": 88, + "line": 3 + }, + "pos": 155, + "start": { + "character": 155, + "column": 0, + "line": 3 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 319, + "column": 75, + "line": 4 + }, + "pos": 244, + "start": { + "character": 244, + "column": 0, + "line": 4 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 402, + "column": 82, + "line": 5 + }, + "pos": 320, + "start": { + "character": 320, + "column": 0, + "line": 5 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 493, + "column": 90, + "line": 6 + }, + "pos": 403, + "start": { + "character": 403, + "column": 0, + "line": 6 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 561, + "column": 67, + "line": 7 + }, + "pos": 494, + "start": { + "character": 494, + "column": 0, + "line": 7 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 636, + "column": 74, + "line": 8 + }, + "pos": 562, + "start": { + "character": 562, + "column": 0, + "line": 8 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 719, + "column": 82, + "line": 9 + }, + "pos": 637, + "start": { + "character": 637, + "column": 0, + "line": 9 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 792, + "column": 72, + "line": 10 + }, + "pos": 720, + "start": { + "character": 720, + "column": 0, + "line": 10 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 872, + "column": 79, + "line": 11 + }, + "pos": 793, + "start": { + "character": 793, + "column": 0, + "line": 11 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 960, + "column": 87, + "line": 12 + }, + "pos": 873, + "start": { + "character": 873, + "column": 0, + "line": 12 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 1033, + "column": 72, + "line": 13 + }, + "pos": 961, + "start": { + "character": 961, + "column": 0, + "line": 13 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 1113, + "column": 79, + "line": 14 + }, + "pos": 1034, + "start": { + "character": 1034, + "column": 0, + "line": 14 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 1201, + "column": 87, + "line": 15 + }, + "pos": 1114, + "start": { + "character": 1114, + "column": 0, + "line": 15 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 1277, + "column": 75, + "line": 16 + }, + "pos": 1202, + "start": { + "character": 1202, + "column": 0, + "line": 16 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 1360, + "column": 82, + "line": 17 + }, + "pos": 1278, + "start": { + "character": 1278, + "column": 0, + "line": 17 + } + }, + { + "code": "security-anchor-rel-noreferrer", + "message": "Security: Anchor with \"target=_blank\" should have rel attribute containing the value \"noreferrer\"", + "end": { + "character": 1451, + "column": 90, + "line": 18 + }, + "pos": 1361, + "start": { + "character": 1361, + "column": 0, + "line": 18 + } + } +]