对特定应用程序的文件权限

File permission to a specific application

我在 Delphi 提出了申请,它是 运行ning Windows Server 2019 每个用户。这些用户通过远程桌面连接到用户会话(组策略)和 运行 应用程序。

是否可以在共享网络地图上打开配置文件只能使用我的应用程序而不是例如记事本?

更一般。存储实际上对用户保密的配置数据的最佳方式是什么?我正在考虑将敏感数据放在数据库中,但仍然很好,例如服务器信息不放在配置文件中而不是“烘焙”中。

这是我的第一个 post 我知道它介于编程和服务器配置之间。否则我的翻译比例似乎不会因为“只有应用程序打开文件”而受到打击。如果这个 post 不完美,请原谅。

我看到了几种可能性:

1° 如果您不想让用户“看到”您的数据,那么您必须对文件内容进行加密。有很多 Delphi encryption/decryption 库。我建议您从 Delphi Encryption Compendium 开始,它在 GitHub.

上免费提供

您可以将数据存储在内存结构中,例如 XML or JSON(Delphi 有内置例程来处理 XML 和 JSON) .在写入光盘之前,您对其进行加密,并在重新加载加密文件后,在以标准方式访问它之前对其进行解密。

2° 使用可从另一个帐户访问的文件,并让您的程序在需要访问该文件时模拟该帐户。

我写了一些代码来简化和演示这种方式。我创建了一个 class TImpersonateUser 有两个方法 LogonLogoff 这将使程序连接到给定的用户帐户并断开连接。

要进行测试,首先使用另一个帐户登录并在某处创建一个文件,例如在文档中。然后登录回您的普通用户代码并启动演示程序(下面的代码)。填写用户名、域和密码(对于域,“.”将仅在本地计算机上进行身份验证)。使用您之前创建的文件的完整路径填写文件名。单击“文件访问”。它应该回答“找不到文件”。然后单击“模拟”,然后再次单击“文件访问”。现在您应该可以访问其他帐户中的文件。单击“还原为自我”并重试“文件访问”,它应该会再次失败。

综上所述,对于您的问题,用户看不到的数据必须在另一个帐户下创建,并且您的应用程序在需要访问数据时模拟另一个帐户。不要忘记在您的程序中以某种方式隐藏用户名和密码。

注意:获得句柄(打开的文件或流)后,您可以 RevertToSelf 并仍然使用句柄(或流)。它保持安全上下文(使用的帐户)直到关闭。这意味着您可以在打开文件前调用登录,打开后立即调用注销(或打开失败)并继续访问文件。

编辑: 我写了一个 blog post with more code.

unit ImpersonateUser;

interface

uses
    Winapi.Windows, System.Classes;

const
    LOGON32_LOGON_NEW_CREDENTIALS  = 9;    // Missing in Delphi

type
    TImpersonateUser = class(TComponent)
    protected
        FUserToken : THandle;
        FErrorCode : DWORD;
    public
        destructor Destroy; override;
        function  Logon(const UserName : String;
                        const Domain   : String;
                        const Password : String) : Boolean;
        procedure Logoff();
        property ErrorCode : DWORD read FErrorCode;
    end;

implementation

{ TImpersonateUser }

destructor TImpersonateUser.Destroy;
begin
    if FUserToken <> 0 then begin
        CloseHandle(FUserToken);
        FUserToken := 0;
    end;

    inherited Destroy;
end;

procedure TImpersonateUser.Logoff;
begin
    if FUserToken <> 0 then begin
        RevertToSelf();   // Revert to our user
        CloseHandle(FUserToken);
        FUserToken := 0;
    end;
end;

function TImpersonateUser.Logon(
    const UserName : String;
    const Domain   : String;
    const Password : String): Boolean;
var
    LoggedOn : Boolean;
begin
    Result := FALSE;
    if FUserToken <> 0 then
        Logoff();

    if UserName = '' then begin // Must at least provide a user name
        FErrorCode := ERROR_BAD_ARGUMENTS;
        Exit;
    end;

    if Domain <> '' then
        LoggedOn := LogonUser(PChar(UserName),
                              PChar(Domain),
                              PChar(Password),
                              LOGON32_LOGON_INTERACTIVE,
                              LOGON32_PROVIDER_DEFAULT,
                              FUserToken)
    else
        LoggedOn := LogonUser(PChar(UserName),
                              PChar(Domain),
                              PChar(Password),
                              LOGON32_LOGON_NEW_CREDENTIALS,
                              LOGON32_PROVIDER_WINNT50,
                              FUserToken);
    if not LoggedOn then begin
        FErrorCode := GetLastError();
        Exit;
    end;

    if not ImpersonateLoggedOnUser(FUserToken) then begin
        FErrorCode := GetLastError();
        Exit;
    end;

    FErrorCode := S_OK;
    Result     := TRUE;
end;

end.

简单演示:

unit ImpersonateUserDemoMain;

interface

uses
    Winapi.Windows, Winapi.Messages,
    System.SysUtils, System.Variants, System.Classes,
    Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
    ImpersonateUser;

type
    TImpersonateUserMainForm = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    UserNameEdit: TEdit;
    DomainEdit: TEdit;
    PasswordEdit: TEdit;
    ImpersonateButton: TButton;
    Label4: TLabel;
    FileNameEdit: TEdit;
    RevertToSelfButton: TButton;
    FileAccessButton: TButton;
    procedure FileAccessButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ImpersonateButtonClick(Sender: TObject);
    procedure RevertToSelfButtonClick(Sender: TObject);
    private
        FImpersonate : TImpersonateUser;
    end;

var
    ImpersonateUserMainForm: TImpersonateUserMainForm;

implementation

{$R *.dfm}

procedure TImpersonateUserMainForm.FileAccessButtonClick(Sender: TObject);
var
    Stream : TFileStream;
begin
    try
        if not FileExists(FileNameEdit.Text) then
            ShowMessage('File not found')
        else begin
            Stream := TFileStream.Create(FileNameEdit.Text, fmOpenRead);
            try
                ShowMessage('File opened');
            finally
                Stream.Free;
            end;
        end;
    except
        on E:Exception do
            ShowMessage(E.Classname + ': ' + E.Message);
    end;
end;

procedure TImpersonateUserMainForm.FormCreate(Sender: TObject);
begin
    UserNameEdit.Text := 'YourUsername';
    DomainEdit.Text   := '.';
    PasswordEdit.Text := 'YourPassword';
    FilenameEdit.Text := 'C:\Users\AnotherUser\Documents\HelloWorld.txt';
    FImpersonate      := TImpersonateUser.Create(Self);
end;

procedure TImpersonateUserMainForm.ImpersonateButtonClick(Sender: TObject);
begin
    if not FImpersonate.Logon(UserNameEdit.Text,
                              DomainEdit.Text,
                              PasswordEdit.Text) then begin
        ShowMessage(Format('Failed with error 0x%X', [FImpersonate.ErrorCode]));
    end
    else
        ShowMessage('Logon OK');
end;

procedure TImpersonateUserMainForm.RevertToSelfButtonClick(Sender: TObject);
begin
    FImpersonate.Logoff;
    ShowMessage('Reverted to self');
end;

end.

DFM 文件:

object ImpersonateUserMainForm: TImpersonateUserMainForm
  Left = 0
  Top = 0
  Caption = 'ImpersonateUserMainForm'
  ClientHeight = 142
  ClientWidth = 331
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 16
    Top = 20
    Width = 49
    Height = 13
    Caption = 'UserName'
  end
  object Label2: TLabel
    Left = 16
    Top = 48
    Width = 35
    Height = 13
    Caption = 'Domain'
  end
  object Label3: TLabel
    Left = 12
    Top = 76
    Width = 46
    Height = 13
    Caption = 'Password'
  end
  object Label4: TLabel
    Left = 16
    Top = 104
    Width = 16
    Height = 13
    Caption = 'File'
  end
  object UserNameEdit: TEdit
    Left = 80
    Top = 16
    Width = 121
    Height = 21
    TabOrder = 0
    Text = 'UserNameEdit'
  end
  object DomainEdit: TEdit
    Left = 80
    Top = 44
    Width = 121
    Height = 21
    TabOrder = 1
    Text = 'DomainEdit'
  end
  object PasswordEdit: TEdit
    Left = 80
    Top = 72
    Width = 121
    Height = 21
    TabOrder = 2
    Text = 'PasswordEdit'
  end
  object ImpersonateButton: TButton
    Left = 232
    Top = 14
    Width = 75
    Height = 25
    Caption = 'Impersonate'
    TabOrder = 3
    OnClick = ImpersonateButtonClick
  end
  object FileNameEdit: TEdit
    Left = 80
    Top = 99
    Width = 121
    Height = 21
    TabOrder = 4
    Text = 'FileNameEdit'
  end
  object RevertToSelfButton: TButton
    Left = 232
    Top = 45
    Width = 75
    Height = 25
    Caption = 'Revert to self'
    TabOrder = 5
    OnClick = RevertToSelfButtonClick
  end
  object FileAccessButton: TButton
    Left = 232
    Top = 76
    Width = 75
    Height = 25
    Caption = 'File access'
    TabOrder = 6
    OnClick = FileAccessButtonClick
  end
end