视窗模拟Apache模块的拉撒路 [英] Windows Impersonation Apache Module in Lazarus

查看:160
本文介绍了视窗模拟Apache模块的拉撒路的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I currently am in the process of porting several Windows desktop applications to a single web site.

目前的设置包括多个SQL服务器后端数据库,使用Windows身份验证(SSPI)只,每个用户/组/角色对特定对象的特定的权利配置。这是方便的,因为应用层不必实现任何访问​​控制。

The current setup includes several SQL server backend databases, configured with Windows Authentication (SSPI) only, and every user/group/role has specific rights on specific objects. Which is convenient, because the application layer doesn't have to implement any access control.

我想以同样的方式把它与Web服务器,Apache的Windows机器上。但对数据库的每一个连接正在使用Apache的帐户进行。这是可以理解和预期,实际上Apache是​​故意给访问公共数据,才能够提供公共的内容。

I'd like to keep it the same way with the web server, an Apache on a Windows machine. But every connection to the databases is being made using Apache's account. That's understandable and expected, in fact Apache is deliberately given access to public data, to be able to deliver public content.

但在情况下,域用户登录(登录过程已经实现)我想的Apache进程处理请求的冒充用户,从而在整个过程中充当他们请求。

But in case a domain user logs in (the login process is already implemented) I'd like the Apache process that handles the request to impersonate that user, and thus act as them during the whole request.

起初,我试过php的<一个href=\"http://www.iis.net/learn/application-frameworks/install-and-configure-php-applications-on-iis/using-fastcgi-to-host-php-applications-on-iis\"相对=nofollow> fastcgi.impersonate 伎俩,使用IIS作为Web服务器。但是,我最终放弃了上,主要是因为:(1)我们必须端口到Apache无论如何,(2)它是PHP特有的,事实证明,我们应该作为一个整体来针对Web服务器...

At first, I tried php's fastcgi.impersonate trick, using IIS as the web server. But I eventually gave up on that, mainly because (1) we had to port to Apache anyway and (2) it was php-specific, and it turned out we should be targeting the web server as a whole...

所以我重定向我的搜索Apache模块。几个月的研究没有给出水果,比 mod_auth_sspi 之类的,这显然ISN等吨什么我正在寻找(身份验证和模拟是两回事)。

So I redirected my search to Apache modules. Months of research gave no fruits, other than mod_auth_sspi and the like, which apparently isn't what I'm looking for (authentication and impersonation are two different things).

最后,我决定把我自己的模块。大多数的101的例子我能找到的都写在C,但我设法找到那些2-3中的拉撒路/ FPC ,这是我一直使用的是什么相当长一段时间,现在,但从来没有这样的事。

Finally I decided to make my own module. Most of the "101" examples I could find are written in C, but I managed to find 2-3 ones in Lazarus/FPC, which is what I've been using for quite a while now, but never for such a task.

我知道我必须建立一个.dll的项目,我知道(或多或少)使用什么单位,我知道像函数的LogonUser() ImpersonateLoggedOnUser()应该是我的工具箱。

I know I have to build a .dll project, I know (more or less) what units to use and I know functions like LogonUser() and ImpersonateLoggedOnUser() should be in my toolbox.

有没有人做过类似的事情?任何人都可以点我朝着正确的方向?

Has anyone done anything similar? Can anyone point me to the right direction?

一个例子是AP preciated,即使它的概念的一个简单证明。这个问题还远远没有要求一个最终的,最终的解决办法。

An example would be appreciated, even if it's a simple proof of concept. This question is far from asking for a final, definitive solution.

推荐答案

我终于想出了以下内容:

I eventually came up with the following:

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.

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

This is by no means a final solution, but it's a start. The logic is the following:


  • 恢复到Apache的帐户。这是的一绝的,如果我们使用的是回收的阿帕奇跟帖说previously模仿别人。

  • Revert to the Apache account. This is a must, in case we are using a recycled Apache thread that previously impersonate someone else.

这是一个名为'WinImpersonatecookie中检索用户的凭据,在的形式,用户名:密码。这需要更多的工作(也许加密凭据,或将其存放在安全的(?)放置在服务器或一些更安全)

Retrieve the user's credentials from a cookie named 'WinImpersonate', in the form of username:password. This needs more work (maybe encrypt the credentials, or store them in a safe(?) place up on the server or something even more secure)

模拟用户,用窗口的帮助单元。

返回 DECLINED ,以便Apache知道我们没有处理该请求,并应继续要求模块正确的处理程序。

Return DECLINED, so Apache knows we didn't handle the request, and it should continue asking modules for the right handler.

有很多顾虑,才能为这个来实现一个体面的安全级别加以解决。其中,保护的凭据,以及浏览器缓存。但正如我所说,这是一个开始,还有一个概念证明。

There are many concerns to be addressed, in order for this to achieve a decent security level. Among others, the protection of the credentials, and the browser cache. But as I said, it's a start, as well as a proof of concept.

您会注意到有两个实用功能,从上面的清单中丢失:

You'll notice that there are two utility functions missing from the above listing:

URLDe code 德codeS一个url-CN codeD字符串:

URLDecode decodes a url-encoded string:

// 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 尝试登录使用提供的凭据的用户,并在成功尝试模仿他:

ChangeLoggedInUser tries to login the user using the credentials supplied, and upon success it tries to impersonate him:

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;

希望有人认为这是有用的。注释是的超过欢迎

这篇关于视窗模拟Apache模块的拉撒路的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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