AWS Cloudfront在发送到原始服务器之前先删除特定的cookie [英] AWS Cloudfront remove particular cookie before sending to origin

查看:105
本文介绍了AWS Cloudfront在发送到原始服务器之前先删除特定的cookie的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在发送到原始服务器之前在AWS Cloudfront中删除特定的cookie。
我必须将所有cookie都发送到源,但名为 _ x_ad_zone 的cookie除外。

I want to remove particular cookie in aws cloudfront before sending to the origin server. I have to send all cookies to origin except cookie named "_x_ad_zone".

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

I could not find any option to remove particular cookie in cloud front configuration. I believe that we have to achieve with lambda, but I have no clue how to do it.

请让我知道如何实现这一目标。

Please let me know how can I achieve the same.


根据答案,我写了以下lambda @ edge解决了我的问题。

Based on the answer, I wrote the following lambda@edge to solve my issue.

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);
};


推荐答案

快速免责声明:将cookie转发到在原始服务器上,CloudFront不仅针对URI和标头(以及查询字符串(如果配置为这样做),还针对浏览器显示的Cookie值(或丢失的Cookie)的唯一组合)缓存响应-仅当响应包含(或丢失)cookie和值的完全相同时,才可以从缓存中提供响应。这对您的缓存命中率不利,但是对于CloudFront来说,这也是完全正确的设计-如果提供了其他cookie,则CloudFront除了假定cookie可能修改返回的响应外别无选择

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

It you must forward cookies, it's best to forward specific cookies.

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

您的解决方案只能通过简单和乐观的测试。在很多情况下,它无法正确处理。 Cookie操作的示例脚本仅是一个简单的示例,并且包含了对此功能的免责声明:

Your solution will only pass simplistic and optimistic tests. There are a number of edge cases it does not handle correctly. The example script for cookie manipulation is only a simple illustration, and includes something of a disclaimer to that effect:


* Header values are not parsed.


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

The first problem is that browsers are free to combine multiple cookies in a single Cookie: header, and your test of headers.cookie[i].value.indexOf(cookieName) will not only match a header with the cookie you want, it will match headers with that cookie plus others... and remove all the cookies in that particular header entry.

如果在查看器请求触发器中使用,则存在使用此解决方案删除太多Cookie的巨大风险。在Origin Request触发器中,它甚至更高,因为已经通过匹配的Cache Behavior的cookie转发配置剥离了cookie并对其进行了规范化,并且CloudFront 确实将多个cookie合并在单个标头行上,至少在某些情况下。

If used in a Viewer Request trigger, there's a significant risk of removing too many cookies with this solution. In an Origin Request trigger, it's even higher, since the cookies have already been stripped and re-canonicalized by the cookie forwarding configuration of the matched Cache Behavior, and CloudFront does combine multiple cookies on a single header row, at least under some conditions.

第二个问题与第一个有关: indexOf()将匹配cookie值以及cookie名称,因此可能会导致cookie value 上的错误匹配-您不想检查它。

The second problem is related to the first: the simple string matching of indexOf() will match cookie values, as well as cookie names, so it's possible to get a false match on a cookie value -- which you don't want to be examining.

第三个问题是您并未真正生成有效的替换值。 CloudFront似乎暂时接受了这一点,但是由于它在技术上是无效的,因此有可能在将来修复。

The third problem is that you're not really generating a valid replacement value. CloudFront seems to accept that, for now, but since it's technically invalid, there's a possibility that this could be "fixed" in the future.

我写了一个Lambda我相信@Edge脚本可以完全处理cookie语义,并且只会准确地删除您要删除的cookie,并保持数据结构整洁。因为我发现这是一个有趣的用例,所以我编写了它,以便它可以匹配任意数量的cookie(不仅仅是一个cookie),并且仅在cookie名称上具有完全区分大小写的字符串。

I've written a Lambda@Edge script that I believe fully handles cookie semantics and will remove only and exactly the cookies you want to remove, and leave the data structures clean. Because I find this to be an interesting use case, I wrote it so that it will match as many cookies as you like -- not just one cookie -- with an exact-string, case-sensitive match, on the cookie name only.

在顶部附近的数组中配置cookie。

The cookies are configured in an array near the top.

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

In your case, with a cookie named __a_x_id would look like this:

const discard = [ '__a_x_id' ]; 

在数组中添加多个cookie名称将全部阻止。

Adding multiple cookie names to the array will block all of them.

这使用Node.js 6.10并与Viewer Request触发器或Origin Request触发器一起使用。如果您根本不进行任何缓存,则可能希望将其用作Origin Request触发器,因为这意味着它的触发频率降低。

This uses Node.js 6.10 and works with either a Viewer Request trigger or an Origin Request trigger. If you are doing any caching at all, you'll probably want to use it as an Origin Request trigger, since that means it fires less often.

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

I'm also pleased to report that in spite of looking a little complicated and doing a fair amount of string splitting and having multiple nested loops, this code has a Lambda execution time in a warm container of consistently less than 1 millisecond, whether or not any cookies are matched and removed.

'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);

};

这篇关于AWS Cloudfront在发送到原始服务器之前先删除特定的cookie的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆