AWS Cloudfront在发送到源之前删除特定cookie

时间:2017-08-29 16:11:05

标签: amazon-web-services cookies amazon-cloudfront

我想在发送到源服务器之前删除aws cloudfront中的特定cookie。 除了名为"_x_ad_zone"的cookie之外,我必须将所有cookie发送到原点。

我找不到任何选项来删除云前端配置中的特定cookie。我相信我们必须用lambda来实现,但我不知道如何做到这一点。

请让我知道如何实现同样目标。

[编辑] 根据答案,我写了下面的lambda @ edge来解决我的问题。

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    const cookieName = '__a_x_id';

    /*
     * Lambda at the Edge headers are array objects.
     *
     * Client may send multiple Cookie headers, i.e.:
     * > GET /viewerRes/test HTTP/1.1
     * > User-Agent: curl/7.18.1 (x86_64-unknown-linux-gnu) libcurl/7.18.1 OpenSSL/1.0.1u zlib/1.2.3
     * > Cookie: First=1; Second=2
     * > Cookie: ClientCode=abc
     * > Host: example.com
     *
     * You can access the first Cookie header at headers["cookie"][0].value
     * and the second at headers["cookie"][1].value.
     *
     * Header values are not parsed. In the example above,
     * headers["cookie"][0].value is equal to "First=1; Second=2"
     */
    console.log(headers.cookie);
    // Delete the cookie if found
    if (headers.cookie) {
        for (let i = 0; i < headers.cookie.length; i++) {
            console.log(headers.cookie[i].value);
            if (headers.cookie[i].value.indexOf(cookieName) >= 0) {
                console.log('Adblocker cookie found and delete: '+headers.cookie[i].value);
                headers.cookie[i].value = "0";
                break;
            }
        }
        request.headers = headers;
    }

    callback(null, request);
};

2 个答案:

答案 0 :(得分:1)

快速免责声明:当Cookie转发到原始服务器时,CloudFront不仅会针对URI和标头(以及查询字符串,如果配置这样做)缓存响应,还会针对唯一的组合浏览器提供的cookie值(或缺少的cookie) - 因此只有当缓存包含(或缺少)完全相同的cookie和值组合时,才能从缓存中提供响应。这对于您的缓存命中率并不好,但当然,它也是CloudFront的完全正确的设计 - 如果提供了不同的cookie,CloudFront没有选择,只能假设cookie可能会修改返回的响应从原点开始,所以cookie必须成为缓存密钥的组成部分。

您必须转发Cookie,最好转发特定的Cookie。

但是,CloudFront有许多与缓存无关的应用程序,因此可能存在这样的解决方案的有效用例。

您的解决方案只会通过简单而乐观的测试。有许多边缘情况它无法正确处理。用于cookie操作的示例脚本只是一个简单的说明,并包含一些免责声明:

* Header values are not parsed.

第一个问题是,浏览器可以在一个Cookie:标头中自由组合多个Cookie,而headers.cookie[i].value.indexOf(cookieName)的测试不仅会将标头与您想要的Cookie匹配,还会匹配标头使用该cookie 加上其他 ...并删除该特定标题条目中的所有cookie。

如果在查看者请求触发器中使用,则使用此解决方案删除过多cookie的风险很大。在原始请求触发器中,它甚至更高,因为cookie已经被匹配的缓存行为的cookie转发配置剥离并重新规范化,并且CloudFront 组合了多个cookie一个标题行,至少在某些条件下。

第二个问题与第一个问题有关:indexOf()的简单字符串匹配将匹配cookie值以及cookie名称,因此可能在cookie上获得错误匹配价值 - 您不想要检查。

第三个问题是你并没有真正产生有效的替代价值。到目前为止,CloudFront似乎接受了这一点,但由于它在技术上无效,因此可能会“修复”#34;在将来。

我已经编写了一个Lambda @ Edge脚本,我认为它完全处理cookie语义,并且只会删除您要删除的cookie,并保持数据结构清晰。因为我发现这是一个有趣的用例,所以我写了它,它将匹配尽可能多的cookie - 不仅仅是一个cookie - 只有cookie名称上的精确字符串,区分大小写的匹配。

Cookie配置在靠近顶部的数组中。

在您的情况下,名为__a_x_id的Cookie看起来像这样:

const discard = [ '__a_x_id' ]; 

向数组添加多个cookie名称将阻止所有这些名称。

这使用Node.js 6.10并使用Viewer Request触发器或Origin Request触发器。如果您正在进行任何缓存,那么您可能希望将其用作原始请求触发器,因为这意味着它的触发频率较低。

我也很高兴地报告说,尽管看起来有点复杂并且进行了大量的字符串拆分并且有多个嵌套循环,但此代码在一个始终小于1的热容器中具有Lambda执行时间毫秒,无论是否匹配和删除任何cookie。

'use strict';

// source: https://stackoverflow.com/a/45970883/1695906

// iterate through all Cookie: headers in a request trigger,
// removing any cookies on the "discard" list, while preserving
// the integrity of any other cookies, including those appearing on the same
// header line, and confirm the resulting "cookie" array to CloudFront 
// requirements by removing any now-empty elements, or the entire array
// if no cookies remain

// configure with one or more cookies to be removed from all requests;
// cookie names are case-sensitive

const discard = [ 'grover', 'big_bird' ]; // friends of cookie monster

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    // does the request have any cookies? skip to the end, if not
    if(headers.cookie)
    {
        const cookies = headers.cookie;

        // iterate each Cookie: header, from last to first;
        // last-to-first makes it simple to splice-out an array element
        // because we then need not keep track of the reduced array length

        for (var n = cookies.length; n--;)
        {
            // there may be multiple cookies per header line; examine them all

            const cval = cookies[n].value.split(/;\ /);
            const vlen = cval.length; // how many we started with

            // check individual cookies on this line, backwards
            for (var m = vlen; m--;)
            {
                // cookie name is to the left of "="
                const cookie_kv = cval[m].split('=')[0];
                // run though each member of "discard" array,
                // removing the cookie if it's a match, 
                // again last to first but for no particular reason, here
                for(var di = discard.length; di--;)
                {
                    if(cookie_kv == discard[di])
                    {
                        cval.splice(m,1); // cookie removed!
                        break; // no need to check any other matches, already gone
                    }
                }
            } // for m

            // if our array of cookies for this header line has now changed in size,
            // we must have deleted some or all of it, so we need to reassemble
            // what remains, or eliminate the entire line

            if(cval.length != vlen)
            {
                if(cval.length === 0) // did we remove everything?
                {
                    // yes? we can eliminate this entire line
                    cookies.splice(n,1); 
                }
                else
                {
                    // no? reassemble the remaining cookies
                    headers.cookie[n].value = cval.join('; '); 
                }
            }
        } // for n

        // if the only cookies present in the request were cookies we removed,
        // we now have a completely empty array in headers.cookie, which
        // CloudFront should consider invalid; clean it up
        if(cookies.length === 0) 
        {
            delete headers.cookie;
        }
    }

    // return control to CloudFront, possibly with our modified request
    return callback(null, request);

};

答案 1 :(得分:0)

为此,您需要编写Lambda@Edge函数来有条件地过滤CloudFront中的cookie。

查看this示例,了解所需操作。另请注意,您需要使用Lambda @ Edge更改原始请求事件中的请求标头。