Skip to content

Commit 2b336a3

Browse files
fix(base64): validate base64 strings (#2779)
This updates the node and browser base64 parsers to validate the input string before parsing.
1 parent ec03fa0 commit 2b336a3

File tree

4 files changed

+33
-0
lines changed

4 files changed

+33
-0
lines changed

packages/util-base64-browser/src/index.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,10 @@ describe("fromBase64", () => {
3535
it("should convert double padded base64 strings to Uint8Arrays", () => {
3636
expect(fromBase64(b64DoublePadded)).toEqual(doublePadded);
3737
});
38+
39+
describe("should reject invalid base64 strings", () => {
40+
it.each(["Rg", "Rg=", "[][]", "-_=="])("rejects '%s'", (value) => {
41+
expect(() => fromBase64(value)).toThrowError();
42+
});
43+
});
3844
});

packages/util-base64-browser/src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ export function fromBase64(input: string): Uint8Array {
5252
let bitLength = 0;
5353
for (let j = i, limit = i + 3; j <= limit; j++) {
5454
if (input[j] !== "=") {
55+
// If we don't check for this, we'll end up using undefined in a bitwise
56+
// operation, in which it will be treated as 0.
57+
if (!(input[j] in alphabetByEncoding)) {
58+
throw new TypeError(`Invalid character ${input[j]} in base64 string.`);
59+
}
5560
bits |= alphabetByEncoding[input[j]] << ((limit - j) * bitsPerLetter);
5661
bitLength += bitsPerLetter;
5762
} else {

packages/util-base64-node/src/index.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,10 @@ describe("fromBase64", () => {
4343
it("should throw when given a number", () => {
4444
expect(() => fromBase64(0xdeadbeefface as any)).toThrow();
4545
});
46+
47+
describe("should reject invalid base64 strings", () => {
48+
it.each(["Rg", "Rg=", "[][]", "-_=="])("rejects '%s'", (value) => {
49+
expect(() => fromBase64(value)).toThrowError();
50+
});
51+
});
4652
});

packages/util-base64-node/src/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
import { fromArrayBuffer, fromString } from "@aws-sdk/util-buffer-from";
22

3+
const BASE64_REGEX = /^[A-Za-z0-9+/]*={0,2}$/;
4+
35
/**
46
* Converts a base-64 encoded string to a Uint8Array of bytes using Node.JS's
57
* `buffer` module.
68
*
79
* @param input The base-64 encoded string
810
*/
911
export function fromBase64(input: string): Uint8Array {
12+
// Node's buffer module allows padding to be omitted, but we want to enforce
13+
// it. So here we ensure that the input represents a number of bits divisible
14+
// by 8. Each character represents 6 bits, so after reducing the fraction we
15+
// end up mulitplying by 3/4 and checking for a remainder.
16+
if ((input.length * 3) % 4 !== 0) {
17+
throw new TypeError(`Incorrect padding on base64 string.`);
18+
}
19+
20+
// Node will just ingore invalid characters, so we need to make sure they're
21+
// properly rejected.
22+
if (!BASE64_REGEX.exec(input)) {
23+
throw new TypeError(`Invalid base64 string.`);
24+
}
25+
1026
const buffer = fromString(input, "base64");
1127

1228
return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);

0 commit comments

Comments
 (0)