понедельник, 22 августа 2016 г.

[Delphi XE2] Indy Parse Cookie Bug

В Delphi XE2 отыскался баг в TIdCookie.ParseServerCookie. Смотрим код:


  function GetLastValueOf(const AName: String; var VValue: String): Boolean;
  var
    I: Integer;
  begin
    Result := False;
    for I := CookieProp.Count-1 downto 0 do
    begin
      if TextIsSame(CookieProp.Names[I], AName) then
      begin
        {$IFDEF HAS_TStrings_ValueFromIndex}
        VValue := CookieProp.ValueFromIndex[I];
        {$ELSE}
        VValue := Copy(CookieProp[I], Pos('=', CookieProp[I])+1, MaxInt); {Do not Localize}
        {$ENDIF}
        Result := True;
        Exit;
      end;
    end;
  end;

...

    if GetLastValueOf('MAX-AGE', S) then begin {Do not Localize}
      FPersistent := True;
      FExpires := StrToFloat(S);
    end
    else if GetLastValueOf('EXPIRES', S) then {Do not Localize}
    begin
      FPersistent := True;
      FExpires := StrToFloat(S);
    end else
    begin
      FPersistent := False;
      FExpires := EncodeDate(9999, 12, 31) + EncodeTime(23, 59, 59, 999);
    end;

    if GetLastValueOf('DOMAIN', S) then {Do not Localize}
    begin
             
      {
        If the user agent is configured to reject "public suffixes" and
        the domain-attribute is a public suffix:

           If the domain-attribute is identical to the canonicalized
           request-host:

              Let the domain-attribute be the empty string.

           Otherwise:

              Ignore the cookie entirely and abort these steps.

           NOTE: A "public suffix" is a domain that is controlled by a
           public registry, such as "com", "co.uk", and "pvt.k12.wy.us".
           This step is essential for preventing attacker.com from
           disrupting the integrity of example.com by setting a cookie
           with a Domain attribute of "com".  Unfortunately, the set of
           public suffixes (also known as "registry controlled domains")
           changes over time.  If feasible, user agents SHOULD use an
           up-to-date public suffix list, such as the one maintained by
           the Mozilla project at <http://publicsuffix.org/>.
      }
    end;

    if Length(S) > 0 then
    begin
      if not IsDomainMatch(AURI.Host, S) then begin
        Exit;
      end;
      FHostOnly := False;
      FDomain := S;
    end else
    begin
      FHostOnly := True;
      FDomain := CanonicalizeHostName(AURI.Host);
    end;

Ошибка происходит если строка S после вызова GetLastValueOf('EXPIRES', S) содержит что-нибудь (Length(S) > 0), а GetLastValueOf('DOMAIN', S) возвращает False.

Такое случается, если на вход TIdCookie.ParseServerCookie поступает строка ACookieText типа такой:

CookieName=CookieValue;Path=/;Expires=Wed, 20-Aug-2017 02:20:00 GMT;

Интересно, что ошибки бы не случилось, если бы параметр VValue у функции GetLastValueOf был объявлен как out, а не как var.

Fix. Для исправления этого бага я сделал класс TVCookieManager, который служит заменой для TIdCookieManager. Взять можно тут: https://github.com/coolsoftware/VCookieManager.
Использовать так:

var
  FixedCookieManager: TVCookieManager;
  IdHTTP: TIdHTTP;
  
  ...
  
  FixedCookieManager := TVCookieManager.Create;
  IdHTTP := TIdHTTP.Create;
  IdHTTP.CookieManager := FixedCookieManager;


===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Комментариев нет:

Отправить комментарий