5

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

因此,在我的第一次尝试中,我拆分了 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 值,并pResponse->SetHeader(pfc, "Set-Cookie:", szNewValue)为每个 cookie 调用,但在这种情况下浏览器只获取最后一个 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设置回响应的最佳方法是什么?

4

3 回答 3

2

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

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

最初发布的解决方案不起作用,因为它为每个 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;
}
于 2013-11-01T18:12:05.983 回答
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 即可再次添加它们。

于 2013-11-19T19:35:06.803 回答
0

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

于 2013-10-15T20:57:48.100 回答