From b747bf8d392102e00a41dc3ddbdcb3bf463b0069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kat=20March=C3=A1n?= Date: Wed, 14 Feb 2018 12:09:33 -0800 Subject: [PATCH] fix(security): tweak strict SRI regex The previous form was vulnerable to ReDoS attacks, by crafting exceptionally long base64 hash strings. This issue only affected consumers using the opts.strict option. --- index.js | 2 +- test/integrity.js | 15 +++++++++------ test/stringify.js | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index ba1bb6d..43c1507 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,7 @@ const SPEC_ALGORITHMS = ['sha256', 'sha384', 'sha512'] const BASE64_REGEX = /^[a-z0-9+/]+(?:=?=?)$/i const SRI_REGEX = /^([^-]+)-([^?]+)([?\S*]*)$/ -const STRICT_SRI_REGEX = /^([^-]+)-([A-Za-z0-9+/]+(?:=?=?))([?\x21-\x7E]*)$/ +const STRICT_SRI_REGEX = /^([^-]+)-([A-Za-z0-9+/=]{44,88})(\?[\x21-\x7E]*)*$/ const VCHAR_REGEX = /^[\x21-\x7E]+$/ class Hash { diff --git a/test/integrity.js b/test/integrity.js index 3a697fb..a35f725 100644 --- a/test/integrity.js +++ b/test/integrity.js @@ -7,20 +7,20 @@ const test = require('tap').test const ssri = require('..') test('toString()', t => { - const sri = ssri.parse('sha512-foo sha256-bar!') + const sri = ssri.parse('sha1-eUN/Xt2hP5wGabl43XqQZt0gWfE= sha256-Qhx213Vjr6GRSEawEL0WTzlb00whAuXpngy5zxc8HYc=') t.equal( sri.toString(), - 'sha512-foo sha256-bar!', + 'sha1-eUN/Xt2hP5wGabl43XqQZt0gWfE= sha256-Qhx213Vjr6GRSEawEL0WTzlb00whAuXpngy5zxc8HYc=', 'integrity objects from ssri.parse() can use toString()' ) t.equal( sri.toString({strict: true}), - 'sha512-foo', + 'sha256-Qhx213Vjr6GRSEawEL0WTzlb00whAuXpngy5zxc8HYc=', 'accepts strict mode option' ) t.equal( sri.toString({sep: '\n'}), - 'sha512-foo\nsha256-bar!', + 'sha1-eUN/Xt2hP5wGabl43XqQZt0gWfE=\nsha256-Qhx213Vjr6GRSEawEL0WTzlb00whAuXpngy5zxc8HYc=', 'accepts separator option' ) t.done() @@ -72,9 +72,12 @@ test('concat()', t => { 'sha512-foo sha512-quux sha1-bar sha1-baz', 'preserves relative order for algorithms between different concatenations' ) + const strictSri = ssri.parse('sha512-WrLorGiX4iEWOOOaJSiCrmDIamA47exH+Bz7tVwIPb4sCU8w4iNqGCqYuspMMeU5pgz/sU7koP5u8W3RCUojGw==') t.equal( - sri.concat('sha1-bar!', {strict: true}).toString(), - 'sha512-foo', + strictSri.concat('sha1-eUN/Xt2hP5wGabl43XqQZt0gWfE=', { + strict: true + }).toString(), + 'sha512-WrLorGiX4iEWOOOaJSiCrmDIamA47exH+Bz7tVwIPb4sCU8w4iNqGCqYuspMMeU5pgz/sU7koP5u8W3RCUojGw==', 'accepts strict mode option' ) t.done() diff --git a/test/stringify.js b/test/stringify.js index 727efbd..53200cb 100644 --- a/test/stringify.js +++ b/test/stringify.js @@ -108,8 +108,8 @@ test('support strict serialization', t => { 'entries that do not conform to strict spec interpretation removed' ) t.equal( - ssri.stringify('sha512-foo sha256-bar', {sep: ' \r|\n\t', strict: true}), - 'sha512-foo \r \n\tsha256-bar', + ssri.stringify('sha512-WrLorGiX4iEWOOOaJSiCrmDIamA47exH+Bz7tVwIPb4sCU8w4iNqGCqYuspMMeU5pgz/sU7koP5u8W3RCUojGw== sha256-Qhx213Vjr6GRSEawEL0WTzlb00whAuXpngy5zxc8HYc=', {sep: ' \r|\n\t', strict: true}), + 'sha512-WrLorGiX4iEWOOOaJSiCrmDIamA47exH+Bz7tVwIPb4sCU8w4iNqGCqYuspMMeU5pgz/sU7koP5u8W3RCUojGw== \r \n\tsha256-Qhx213Vjr6GRSEawEL0WTzlb00whAuXpngy5zxc8HYc=', 'strict mode replaces non-whitespace characters in separator with space' ) t.done()