jetbridge / cdk-nextjs

Deploy a NextJS application using AWS CDK
https://constructs.dev/packages/cdk-nextjs-standalone
Apache License 2.0
260 stars 43 forks source link

Consider using native `node:crypto` to sign requests in sign-fn-url #165

Closed dreamorosi closed 8 months ago

dreamorosi commented 8 months ago

The src/lambdas/sign-fn-url.ts function uses the @aws-crypto/sha256-js module to sign requests to the function url and provide IAM authentication.

The same module is used by other AWS projects and works just fine, however it's meant to be an isomorphic package. This means it contains code that make it work on both Node.js and the browser.

For Lambda, and specifically for all the current Node.js runtimes, most of the package is not needed since modern implementations of node:crypto can do the job just fine.

In other projects of mine I have replaced the package with the following implementation, which should be a drop-in class for the interfaces required by the SignatureV4 function:

import {
  createHash,
  createHmac,
  type BinaryLike,
  type Hmac,
  type KeyObject,
} from "node:crypto";

class Sha256 {
  private readonly hash: Hmac;

  public constructor(secret?: unknown) {
    this.hash = secret
      ? createHmac("sha256", secret as BinaryLike | KeyObject)
      : createHash("sha256");
  }

  public digest(): Promise<Uint8Array> {
    const buffer = this.hash.digest();

    return Promise.resolve(new Uint8Array(buffer.buffer));
  }

  public update(array: Uint8Array): void {
    this.hash.update(array);
  }
}

The alternative implementation helps reduce the bundle by ~7%, which is admittedly not much, but it's one less dependency to maintain.

Using @aws-crypto/sha256-js:

npx esbuild --bundle ./src/lambdas/sign-fn-url.ts --target="node18" --platform="node" --outfile="assets/lambdas/sign-fn-url/index.js" --sourcemap

  assets/lambdas/sign-fn-url/index.js      185.7kb
  assets/lambdas/sign-fn-url/index.js.map  291.1kb

Using alternate implementation

npx esbuild --bundle ./src/lambdas/sign-fn-url.ts --target="node18" --platform="node" --outfile="assets/lambdas/sign-fn-url/index.js" --sourcemap

  assets/lambdas/sign-fn-url/index.js      172.5kb
  assets/lambdas/sign-fn-url/index.js.map  274.9kb
bestickley commented 8 months ago

Hey @dreamorosi, excellent suggestion! However, a Q4 2023 CloudFront feature (OAC Lambda) will negate the need for this CloudFront function. When that feature lands, we can enable it by default so Nextjs Lambdas aren't open to world and more secure. I'll keep this in mind though for the future!