Skip to content

Commit 0e58d2e

Browse files
drhinolukeed
andauthored
chore: improve basic-auth example (#1711)
* improvements - Better validation when the Authorization header does not contain a space. - Normalizes the decoded string once. Both the user and password must be normalized. -- Strictly define NFC encoding as per RFC: 3.3.2.4 & 4.2.2.4 (even though it's the default): "Normalization Rule: Unicode Normalization Form C (NFC) MUST be applied to all characters." - Figured out what control characters are: https://tools.ietf.org/html/rfc5234#appendix-B.1 Left column and bottom right value of (Hx column): -- http://www.asciitable.com/index/asciifull.gif -- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes ( "\0" equals "\x00" ) ( try catch fails when decoded.match(...) does not return an array ) * Apply suggestions from code review Co-authored-by: Luke Edwards <[email protected]>
1 parent 8f8c392 commit 0e58d2e

File tree

1 file changed

+19
-16
lines changed

1 file changed

+19
-16
lines changed

products/workers/src/content/examples/basic-auth.md

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ tags:
2020
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication
2121
* @see https://tools.ietf.org/html/rfc7617
2222
*
23-
* The user and password MUST NOT contain any control characters.
24-
* @see https://tools.ietf.org/html/rfc5234#appendix-B.1
25-
*
2623
* A user-id containing a colon (":") character is invalid, as the
2724
* first colon in a user-pass string separates user and password.
2825
*/
@@ -114,23 +111,29 @@ function basicAuthentication(request) {
114111

115112
const [scheme, encoded] = Authorization.split(' ')
116113

117-
// The Authorization header must look like "Basic user:encoded".
118-
if (scheme !== 'Basic') throw new BadRequestException('Malformed authorization header.')
119-
120-
// Decode the base64 value.
121-
const decoded = atob(encoded)
114+
// The Authorization header must start with "Basic", followed by a space.
115+
if (!encoded || scheme !== 'Basic') {
116+
throw new BadRequestException('Malformed authorization header.')
117+
}
122118

123-
// The username & password are split by the first colon.
124-
const seperatorPosition = decoded.indexOf(':')
125-
126-
// NOTE: Without `.normalize()` unicode characters could fail verification.
119+
// Decodes the base64 value and performs unicode normalization.
120+
// @see https://datatracker.ietf.org/doc/html/rfc7613#section-3.3.2 (and #section-4.2.2)
127121
// @see https://dev.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
122+
const decoded = atob(encoded).normalize()
123+
124+
// The username & password are split by the first colon.
125+
//=> example: "username:password"
126+
const index = decoded.indexOf(':')
128127

128+
// The user & password are split by the first colon and MUST NOT contain control characters.
129+
// @see https://tools.ietf.org/html/rfc5234#appendix-B.1 (=> "CTL = %x00-1F / %x7F")
130+
if (index === -1 || /[\0-\x1F\x7F]/.test(decoded)) {
131+
throw new BadRequestException('Invalid authorization value.')
132+
}
133+
129134
return {
130-
// The username is the value before the first colon.
131-
user: decoded.substring(0, seperatorPosition).normalize(),
132-
// The password is everything after the first colon.
133-
pass: decoded.substring(seperatorPosition + 1).normalize(),
135+
user: decoded.substring(0, index),
136+
pass: decoded.substring(index + 1),
134137
}
135138
}
136139

0 commit comments

Comments
 (0)