【问题标题】:How to set multiple cookies in ISAPI filter如何在 ISAPI 过滤器中设置多个 cookie
【发布时间】:2013-07-13 00:29:54
【问题描述】:

我在 ISAPI 过滤器中设置多个 cookie 时遇到问题。我想在所有 cookie 中添加 HttpOnly 标志。

所以,在我的第一次尝试中,我拆分了 cookie 值并添加了 HttpOnly 标志,然后将它们组合成一个字符串,最后调用 pResponse->SetHeader(pfc, "Set-Cookie:", szNewValue),浏览器只获取第一个 cookie 值。

第一次尝试代码:

cbValue = sizeof(szValue) / sizeof(szValue[0]);
        if (pResponse->GetHeader(pfc, "Set-Cookie:", szValue, &cbValue))
        {
            char szNewValue[MAX_URI_SIZE] = "";
            char* token = NULL;
            char* context = NULL;
            char delim[] = ",";

            // szValue format like 
            // "Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly,Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly"
            // After first split
            // token = "Language=en; expires=Sat"
            // context = " 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly,Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly"
            token = strtok_s(szValue, delim, &context);
            while (token != NULL)
            {
                strcat_s(szNewValue, token);
                if (NULL != context)
                {
                    if (' ' != context[0] && !strstr(token, "HttpOnly"))
                    {
                        strcat_s(szNewValue, "; HttpOnly");
                    }

                    // context[0] = ' ' means it split the one whole cookie, not an entire cookie, we need append ","
                    // context[0] != '\0' means other cookies after, we need append delimiter ","
                    if (' ' == context[0] || '\0' != context[0])
                    {
                        strcat_s(szNewValue, ",");
                    }
                }
                // NULL, function just re-uses the context after the first read.
                token = strtok_s(NULL, delim, &context);
            }
            if (!pResponse->SetHeader(pfc, "Set-Cookie:", szNewValue))
            {
                // Fail securely - send no cookie!
                pResponse->SetHeader(pfc,"Set-Cookie:","");
            }

在第二次尝试中,我拆分了 cookie 值,并为每个 cookie 调用 pResponse->SetHeader(pfc, "Set-Cookie:", szNewValue),但在这种情况下浏览器只获取最后一个 cookie。

第二次尝试代码:

cbValue = sizeof(szValue) / sizeof(szValue[0]);
        if (pResponse->GetHeader(pfc, "Set-Cookie:", szValue, &cbValue))
        {
            char szNewValue[MAX_URI_SIZE] = "";
            char* token = NULL;
            char* context = NULL;
            char delim[] = ",";

            // szValue format like 
            // "Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly,Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly"
            // After first split
            // token = "Language=en; expires=Sat"
            // context = " 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly,Language=en; expires=Sat, 15-Jul-2113 02:46:27 GMT; path=/; HttpOnly"
            token = strtok_s(szValue, delim, &context);
            while (token != NULL)
            {
                strcat_s(szNewValue, token);
                if (NULL != context)
                {
                    if (' ' != context[0] && !strstr(token, "HttpOnly"))
                    {
                        strcat_s(szNewValue, "; HttpOnly");
                    }

                    // context[0] = ' ' means it split the one whole cookie, not an entire cookie, we need append ","
                    // context[0] != '\0' means other cookies after, we need append delimiter ","
                    if (' ' == context[0])// || '\0' != context[0])
                    {
                        strcat_s(szNewValue, ",");
                    }
                    if (' ' != context[0])
                    {
                        pResponse->SetHeader(pfc, "Set-Cookie:", szNewValue);
                        strcpy(szNewValue, "");
                    }
                }
                // NULL, function just re-uses the context after the first read.
                token = strtok_s(NULL, delim, &context);
            }

我在 IE10+Win2008 R2 中执行此操作。在这两种情况下,结果 cookie 字符串的格式都正确。有人对此有任何线索吗?

这个问题的存在基本上是因为当您调用GetHeader 时,您会在一个逗号分隔的字符串中收到所有cookie。使用 SetHeader 方法将所有 cookie 设置回响应的最佳方法是什么?

【问题讨论】:

    标签: c++ winapi iis cookies isapi


    【解决方案1】:

    我正在寻找这个问题的解决方案,发现很多不正确的响应。

    这篇文章让我找到了解决方案。

    最初发布的解决方案不起作用,因为它对每个 cookie 都使用了 SetHeader。 SetHeader 每次调用时都会替换“Set-Cookie:”标头,因此只设置了最后一个 Cookie。我没有使用 SetHeader,而是对每个 cookie 使用 AddHeader。但是,在第一次使用 AddHeader 之前,我使用带有“”的 SetHeader 来“清空”“Set-Cookie:”标头。

    这适用于我使用 IIS5.1 和 IIS7.0

    此解决方案也适用于 ASP Session Id cookie。

    我知道 Classic ASP 是一项古老的技术,但它仍在使用中,我们需要这样的解决方案。

    这是我的完整代码:

    #include <windows.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <httpfilt.h>
    
    BOOL WINAPI __stdcall GetFilterVersion(HTTP_FILTER_VERSION *pVer)
    {
        pVer->dwFlags = SF_NOTIFY_SEND_RESPONSE | SF_NOTIFY_ORDER_HIGH | SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT;
    
        pVer->dwFilterVersion = HTTP_FILTER_REVISION;
    
        strcpy_s(pVer->lpszFilterDesc, sizeof(pVer->lpszFilterDesc), "httpOnly Filter, Version 1.0. JCGalvezV.");
    
        return TRUE;
    }
    
    DWORD WINAPI __stdcall HttpFilterProc(HTTP_FILTER_CONTEXT *pfc, DWORD NotificationType, VOID *pvData)
    {
        DWORD   cbBuffer;
      char lszBuffer[2000], lszNewBuffer[2000];
      HTTP_FILTER_PREPROC_HEADERS *pFPH = (HTTP_FILTER_PREPROC_HEADERS *)pvData;
    
      switch (NotificationType)
      {
        case SF_NOTIFY_SEND_RESPONSE :
          cbBuffer = sizeof(lszBuffer);
          if (pFPH->GetHeader(pfc, "Set-Cookie:", lszBuffer, &cbBuffer))
          {
            char* token = NULL;
            char* context = NULL;
            char delim[] = ",";
    
            // Delete previous cookies
    
            pFPH->SetHeader(pfc, "Set-Cookie:", "");
    
            token = strtok_s(lszBuffer, delim, &context);
            while (token != NULL)
            {
              strcpy_s(lszNewBuffer, sizeof(lszNewBuffer), token);
              if (!strstr(token, "httpOnly"))
                strcat_s(lszNewBuffer, sizeof(lszNewBuffer), "; httpOnly");
    
              // AddHeader instead of SetHeader.
    
              pFPH->AddHeader(pfc, "Set-Cookie:", lszNewBuffer);
    
              // next token
              token = strtok_s(NULL, delim, &context);
            }
    
          }
          break;
        default :
          break;                
        }
    
        return SF_STATUS_REQ_NEXT_NOTIFICATION;
    }
    

    【讨论】:

    • 您应该使用_countof(lszNewBuffer) 而不是sizeof(lszNewBuffer)strcpy_sstrcat_s,因为它需要字符数而不是字节数。在这里它可以工作,因为两者都是相等的,因为字符串是 ANSI。
    【解决方案2】:

    我遇到了同样的问题,我需要联系微软来解决这个问题。当您收到多个 cookie 时,您将收到一个完整的字符串,其中所有 cookie 用逗号分隔。 这项工作包括分离每个 cookie,然后分别为每个 cookie 调用 SetHeader 方法。

    重要的是每个 cookie 都必须有一个唯一的名称-值对 (http://www.quirksmode.org/js/cookies.html),以便可以正确映射每个更改。

    伪代码解决方案

    pResponse->GetHeader(pfc, "Set-Cookie:", szValue, &cbValue)
    
    // split cookies here
    
    foreach separated cookie
        pResponse->SetHeader(pfc, "Set-Cookie:", oneCookie)
    

    这样,您无需清除所有 cookie 即可再次添加它们。

    【讨论】:

      【解决方案3】:

      您的第一次尝试比第二次要好,因为您应该只设置一次标题。我认为您的字符串解析算法有点偏离。我会尝试简化一些。首先将标题拆分为每个 cookie 的字符串。然后根据需要修改 cookie 以添加 http only 属性,然后将 cookie 组合回单个标头。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-11
        • 2012-02-11
        • 2018-03-15
        • 1970-01-01
        相关资源
        最近更新 更多