【问题标题】:Windows Impersonation Apache Module in LazarusLazarus 中的 Windows 模拟 Apache 模块
【发布时间】:2013-10-13 07:04:53
【问题描述】:

我目前正在将几个 Windows 桌面应用程序移植到一个网站。

当前设置包括多个 SQL Server 后端数据库,仅配置了 Windows 身份验证 (SSPI),并且每个用户/组/角色都对特定对象具有特定权限。这很方便,因为应用层不必实现任何访问​​控制。

我想保持与 Web 服务器相同的方式,即 Windows 机器上的 Apache。但是每个与数据库的连接都是使用 Apache 的帐户进行的。这是可以理解和预期的,事实上 Apache 被刻意授予访问公共数据的权限,以便能够提供公共内容。

但如果域用户登录(登录过程已经实现),我希望处理请求的 Apache 进程模拟该用户,从而在整个过程中充当他们请求。

起初,我尝试了 php 的fastcgi.impersonate 技巧,使用 IIS 作为 Web 服务器。但我最终放弃了,主要是因为(1)无论如何我们都必须移植到 Apache 以及(2)它是特定于 php 的,结果我们应该将整个 Web 服务器作为目标......

所以我将搜索重定向到 Apache 模块。几个月的研究没有结果,除了mod_auth_sspi 等,这显然不是我想要的(身份验证和模拟是两个不同的东西)。

最后我决定制作自己的模块。我能找到的大多数“101”示例都是用 C 编写的,但我设法在 Lazarus/FPC 中找到了 2-3 个示例,这是我已经使用了很长时间的东西,但从不做这样的任务。

我知道我必须构建一个 .dll 项目,我(或多或少)知道要使用哪些单元,并且我知道像 LogonUser()ImpersonateLoggedOnUser() 这样的函数应该在我的工具箱中。

有没有人做过类似的事情?谁能指出我正确的方向?

如果是一个简单的概念证明,我们将不胜感激。这个问题远不是要求一个最终的、确定的解决方案。

【问题讨论】:

  • 不幸的是,我现在对 SQL Server 和 Apache 模块几乎一无所知。对不起:-/

标签: windows apache module impersonation lazarus


【解决方案1】:

我最终想出了以下几点:

library mod_winimpersonate;

{$mode objfpc}{$H+}

uses SysUtils, Windows, httpd, apr, Classes;

function DefaultHandler(r: Prequest_rec): Integer; cdecl;
  Var
    cookies:TStringList;
    logindata,username,password:String;
    p:Integer;
  begin
  RevertToSelf;
  cookies:=TStringList.Create;
  cookies.Delimiter:=';';
  cookies.DelimitedText:=apr_table_get(r^.headers_in,'COOKIE');
  logindata:=URLDecode(cookies.Values['WinImpersonate']);
  If Length(logindata)>0 then
    Begin
    p:=Pos(':',logindata);
    username:=LeftStr(logindata,p-1);
    password:=RightStr(logindata,Length(logindata)-p);
    ChangeLoggedInUser(username,password,'');
    End;
  Result:=DECLINED;
  end;

procedure RegisterHooks(p: Papr_pool_t); cdecl;
  begin
  ap_hook_handler(@DefaultHandler, nil, nil, APR_HOOK_REALLY_FIRST);
  end;

var
  TheModule: module;

exports TheModule name 'winimpersonate_module';

begin
FillChar(TheModule, sizeof(TheModule), 0);
STANDARD20_MODULE_STUFF(TheModule);
with TheModule do
  begin
  name := 'mod_winimpersonate.dll';
  register_hooks := @RegisterHooks;
  end;
end.

这绝不是最终的解决方案,但它是一个开始。逻辑如下:

  • 恢复到 Apache 帐户。这是必须的,以防我们使用以前冒充其他人的回收 Apache 线程。

  • 从名为“WinImpersonate”的 cookie 中检索用户的凭据,格式为 username:password。这需要更多的工作(也许加密凭据,或者将它们存储在服务器上的安全(?)地方或更安全的地方)

  • windows单元的帮助下模拟用户。

  • 返回 DECLINED,这样 Apache 就知道我们没有处理请求,它应该继续向模块询问正确的处理程序。

为了达到不错的安全级别,有许多问题需要解决。其中包括凭据保护和浏览器缓存。但正如我所说,这是一个开始,也是一个概念证明。

您会注意到上面的清单中缺少两个实用函数:

URLDecode 解码一个 url 编码的字符串:

// Convert URLEncoded string to utf8 string
function URLDecode(const s: String): String;
  var
    sAnsi: String;
    sUtf8: String;
    sWide: WideString;
    i, len: Cardinal;
    ESC: string[2];
    CharCode: integer;
    c: char;
  begin
  sAnsi := PChar(s);
  SetLength(sUtf8, Length(sAnsi));
  i := 1;
  len := 1;
  while (i <= Cardinal(Length(sAnsi))) do 
    begin
    if (sAnsi[i] <> '%') then 
      begin
      if (sAnsi[i] = '+') then c := ' '  else c := sAnsi[i];
      sUtf8[len] := c;
      Inc(len);
      end 
    else 
      begin
      Inc(i);
      ESC := Copy(sAnsi, i, 2);
      Inc(i, 1);
      try
        CharCode := StrToInt('$' + ESC);
        c := Char(CharCode);
        sUtf8[len] := c;
        Inc(len);
      except 
        end;
      end;
    Inc(i);
    end;
  Dec(len);
  SetLength(sUtf8, len);
  sWide := UTF8Decode(sUtf8);
  len := Length(sWide);
  Result := sWide;
  end;

ChangeLoggedInUser 尝试使用提供的凭据登录用户,并在成功后尝试冒充他:

Function ChangeLoggedInUser(username, password, domain: string):Boolean;
  var
    creds: Cardinal;
  begin
  Result:=False;
  try
    if LogonUser(PChar(username)
        ,PChar(domain)
        ,PChar(password)
        ,LOGON32_LOGON_NETWORK_CLEARTEXT
        ,LOGON32_PROVIDER_DEFAULT
        ,creds
        ) then
      begin
      ImpersonateLoggedOnUser(creds);
      Result:=True;
      end;
  finally
    //wipe the memory for security
    FillChar(username,SizeOf(username),#0);
    FillChar(password,SizeOf(username),#0);
    FillChar(domain,SizeOf(username),#0);
    end;  //try-finally
  end;

希望有人觉得这很有用。评论非常受欢迎

【讨论】:

    猜你喜欢
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 1970-01-01
    • 2019-12-26
    • 1970-01-01
    • 2019-08-17
    • 2013-07-03
    相关资源
    最近更新 更多