windows - 特定应用程序的文件权限

标签 windows delphi file-permissions windows-server group-policy

我在 Delphi 中制作了应用程序,它在每个用户的 Windows Server 2019 上运行。这些用户通过远程桌面连接到用户 session (组策略)并运行应用程序。

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

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

这是我的第一篇文章,我知道它是在编程和服务器配置之间。否则,我的翻译比例似乎不会受到“仅应用程序打开文件”的影响。如果这篇文章不完美,我的借口。

最佳答案

我看到了几种可能性:

1° 如果您不希望用户“看到”您的数据,那么您必须对文件内容进行加密。 Delphi有很多加密/解密库。我建议你从Delphi Encryption Compendium开始可在 GitHub 上免费获取。

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

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

我编写了一些代码用于以这种方式进行简化和演示。我创建了一个类 TImpersonateUser,它有两个方法 LogonLogoff,这将使程序连接到给定的用户帐户并与其断开连接。

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

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

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

编辑:我写了一个blog postmore 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

关于windows - 特定应用程序的文件权限,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68457656/

相关文章:

multithreading - Synchronize() 挂起线程

java - 授予 ftp FILE java 权限

sql-server - 使用 PHP、ODBC 和 Windows 身份验证连接到 SQL Server

windows - 如何从当前文件夹以管理员权限运行 PowerShell?

delphi - Delphi 2010 中的 Rtti 数据操作和一致性

linux - Jenkins `Make gradlew executable` 选项不使`gradelw 可执行

php - netbeans php插件使用FTP上传文件时如何控制文件权限

c++ - 如何使用CMake更改构建机器类型

windows - 批处理日期时间在上午 10 点之前中断 Windows 8

c# - 通过代码获取文件 tnsnames.ora 的位置