Cloudfront Lambda@edge set-cookie标头不工作

发布于 2025-02-11 23:13:47 字数 3986 浏览 1 评论 0原文

我有一个CloudFront Distribution,该发行版在Viewer请求和查看器响应中使用2 lambda@edge函数。

在该应用中,将有一个第一个请求,该请求在查询字符串上具有令牌,然后有一系列的请求,其中包含“ cookie”标题的令牌。

我根据查看器请求从“ querystring”中验证令牌。验证后,我将令牌添加到查看器响应中,作为cookie。

问题是,我可以在客户端浏览器上看到“ set-cookie”标头,但没有设置任何cookie。因此,以下请求不包括任何cookie标头。当查询字符串中没有JWT时,我需要从cookie验证令牌。

查看器请求代码:

const crypto = require("crypto");

var response401 = {
    statusCode: 401,
    statusDescription: 'Unauthorized'
};

exports.handler = async (event, context) => {
    const request = event.Records[0].cf.request;
    const key = "SECRET KEY";
    const token = event.Records[0].cf.request.querystring.split("jwt=")[1];
  
    if(!token){
        console.log("Missing authorization token.");
        return response401;
    }
    
    try {
        jwt_decode(token,key)
    } catch (error) {
        console.log(error);
        return response401;
    }
    return request;
};


function jwt_decode(token, key, noVerify, algorithm) {
  // check token
  if (!token) {
    throw new Error("No token supplied");
  }
  // check segments
  var segments = token.split(".");
  if (segments.length !== 3) {
    throw new Error("Not enough or too many segments");
  }

  // All segment should be base64
  var headerSeg = segments[0];
  var payloadSeg = segments[1];
  var signatureSeg = segments[2];
  
  // base64 decode and parse JSON
  var header = JSON.parse(_base64urlDecode(headerSeg));
  var payload = JSON.parse(_base64urlDecode(payloadSeg));

  if (!noVerify) {
    var signingMethod = "sha256";
    var signingType = "hmac";

    // Verify signature. `sign` will return base64 string.
    var signingInput = [headerSeg, payloadSeg].join(".");

    if (!_verify(signingInput, key, signingMethod, signingType, signatureSeg)) {
      throw new Error("Signature verification failed");
    }

    // Support for nbf and exp claims.
    // According to the RFC, they should be in seconds.
    if (payload.nbf && Date.now() < payload.nbf * 1000) {
      throw new Error("Token not yet active");
    }

    if (payload.exp && Date.now() > payload.exp * 1000) {
      throw new Error("Token expired");
    }
  }

  return payload;
}

function _verify(input, key, method, type, signature) {
  if (type === "hmac") {
    console.log(signature, _sign(input, key, method));
    return signature === _sign(input, key, method);
  } else {
    throw new Error("Algorithm type not recognized");
  }
}

function _sign(input, key, method) {
  return crypto.createHmac(method, key).update(input).digest("base64url");
}

function _base64urlDecode(str) {
  return Buffer.from(str, "base64").toString("utf-8");
}


和查看器响应代码

const crypto = require("crypto");

var response401 = {
    statusCode: 401,
    statusDescription: 'Unauthorized'
};

exports.handler = async (event, context) => {

    try {
     
    const response = event.Records[0].cf.response;
    const token = event.Records[0].cf.request.querystring.split("jwt=")[1];
    const headers = response.headers;
   
    const headerNameSrc = 'X-Amz-Meta-Last-Modified';
    const headerNameDst = 'Last-Modified';

    if (headers[headerNameSrc.toLowerCase()]) {
        headers[headerNameDst.toLowerCase()] = [{
            key: headerNameDst,
            value: headers[headerNameSrc.toLowerCase()][0].value,
        }];
        console.log(`Response header "${headerNameDst}" was set to ` +
                    `"${headers[headerNameDst.toLowerCase()][0].value}"`);
    }
   
    const cookie = `token=${token}; Secure; HttpOnly; Max-Age=18000; SameSite=None`;
    response.headers['set-cookie'] = [{
      key : "set-cookie",
      value : cookie
    }];

    return response;
    } catch (error) {
         console.log(error);
        return response401;
    }
    
};

所以我该如何解决问题?是否缺少CloudFront配置?

I have a CloudFront distribution which uses 2 Lambda@Edge functions at Viewer Request and Viewer Response.

In the app, there will be a first request which has a token at query string, and following series of requests which has the token at "cookie" header.

I validate the token from "querystring" at viewer request. After validation, I'm adding the token to Viewer Response as a cookie.

The problem is, I can see the "set-cookie" header at client browser, but it doesn't set any cookies. Thus, the following requests doesn't include any cookie headers. I need to validate the token from cookie when there is no jwt in query string.

Viewer Request Code:

const crypto = require("crypto");

var response401 = {
    statusCode: 401,
    statusDescription: 'Unauthorized'
};

exports.handler = async (event, context) => {
    const request = event.Records[0].cf.request;
    const key = "SECRET KEY";
    const token = event.Records[0].cf.request.querystring.split("jwt=")[1];
  
    if(!token){
        console.log("Missing authorization token.");
        return response401;
    }
    
    try {
        jwt_decode(token,key)
    } catch (error) {
        console.log(error);
        return response401;
    }
    return request;
};


function jwt_decode(token, key, noVerify, algorithm) {
  // check token
  if (!token) {
    throw new Error("No token supplied");
  }
  // check segments
  var segments = token.split(".");
  if (segments.length !== 3) {
    throw new Error("Not enough or too many segments");
  }

  // All segment should be base64
  var headerSeg = segments[0];
  var payloadSeg = segments[1];
  var signatureSeg = segments[2];
  
  // base64 decode and parse JSON
  var header = JSON.parse(_base64urlDecode(headerSeg));
  var payload = JSON.parse(_base64urlDecode(payloadSeg));

  if (!noVerify) {
    var signingMethod = "sha256";
    var signingType = "hmac";

    // Verify signature. `sign` will return base64 string.
    var signingInput = [headerSeg, payloadSeg].join(".");

    if (!_verify(signingInput, key, signingMethod, signingType, signatureSeg)) {
      throw new Error("Signature verification failed");
    }

    // Support for nbf and exp claims.
    // According to the RFC, they should be in seconds.
    if (payload.nbf && Date.now() < payload.nbf * 1000) {
      throw new Error("Token not yet active");
    }

    if (payload.exp && Date.now() > payload.exp * 1000) {
      throw new Error("Token expired");
    }
  }

  return payload;
}

function _verify(input, key, method, type, signature) {
  if (type === "hmac") {
    console.log(signature, _sign(input, key, method));
    return signature === _sign(input, key, method);
  } else {
    throw new Error("Algorithm type not recognized");
  }
}

function _sign(input, key, method) {
  return crypto.createHmac(method, key).update(input).digest("base64url");
}

function _base64urlDecode(str) {
  return Buffer.from(str, "base64").toString("utf-8");
}


And the Viewer Response Code

const crypto = require("crypto");

var response401 = {
    statusCode: 401,
    statusDescription: 'Unauthorized'
};

exports.handler = async (event, context) => {

    try {
     
    const response = event.Records[0].cf.response;
    const token = event.Records[0].cf.request.querystring.split("jwt=")[1];
    const headers = response.headers;
   
    const headerNameSrc = 'X-Amz-Meta-Last-Modified';
    const headerNameDst = 'Last-Modified';

    if (headers[headerNameSrc.toLowerCase()]) {
        headers[headerNameDst.toLowerCase()] = [{
            key: headerNameDst,
            value: headers[headerNameSrc.toLowerCase()][0].value,
        }];
        console.log(`Response header "${headerNameDst}" was set to ` +
                    `"${headers[headerNameDst.toLowerCase()][0].value}"`);
    }
   
    const cookie = `token=${token}; Secure; HttpOnly; Max-Age=18000; SameSite=None`;
    response.headers['set-cookie'] = [{
      key : "set-cookie",
      value : cookie
    }];

    return response;
    } catch (error) {
         console.log(error);
        return response401;
    }
    
};

So, how can I solve the problem? Are there any missing CloudFront configuration?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文