簡體   English   中英

保護Delphi連接字符串免受黑客攻擊

[英]Protect Delphi Connection String From Hack

我們有一個delphi應用程序,使用tadoconnection連接sql server數據庫時出現的問題是,當我們在運行exe文件時打開資源黑客時,它清楚地顯示了連接字符串,任何人都可以連接到我們的服務器

下面顯示的示例代碼描述了問題 在此處輸入圖片說明

您沒有使用資源黑客。 如果您的字符串存儲在資源中,它們將更易於查找和查看。

相反,您使用的是內存掃描程序,它可以在程序運行時查看程序的原始內存。 最終,您必須在內存中創建一個連接字符串才能傳遞給數據庫引擎。 如果黑客可以訪問應用程序及其內存,則他們可以使用其數據的應用程序。 具有這種訪問權限的專門黑客將能夠在使用該字符串時搶劫該字符串。

但是您可以采取一些措施,使休閑黑客更難。

一方面,禁止非管理員用戶訪問您的應用。 當用戶運行掃描儀應用程序時,它可能有權訪問由同一用戶運行的其他應用程序中的內存。 在不同的用戶上下文或提升的流程中運行您的應用程序。 用戶運行的應用程序無法訪問其他用戶正在運行的其他應用程序的內存,除非他/她被明確授予他們許可,或者他/她是管理員。 如果黑客有權訪問您的應用程序,則所有選擇都將關閉。

另外,將字符串分成較小的子字符串,需要時可以將其串聯。 動態建立連接字符串。 這樣,如果黑客嘗試瀏覽磁盤上的EXE文件本身,子字符串就不會存儲在一個地方。

而且, 切勿將敏感的憑據存儲在以開頭的應用程序代碼中 將它們存儲在外部,並對其進行加密。 僅在絕對需要時才將它們檢索到內存中,並在使用SecureZeroMemory()使用SecureZeroMemory()安全銷毀該內存的內容。 如果您需要在內存中保留憑據或連接字符串超過幾毫秒,請在不積極使用內存時考慮使用CryptProtectMemory()對內存進行加密。

將連接字符串拼湊起來需要花費的工作越多,一個隨意的黑客也將不得不做更多的工作。 但是,專門的黑客只會等到您完成所有工作后,才在使用它時從內存中拔出最后一個字符串,因此您必須盡一切努力防止訪問內存。

  1. 確保您的密碼分開存儲,並符合您的要求。*
  2. 確保您的連接不保留密碼。 即Connection.Properties必須包含'Persist Security Info=False'
  3. 設置Connection. LoginPromptTrue
  4. OnLogin事件實現一個處理程序,在該事件中,您加載,解密並將密碼提供給Connection.Open調用。
  5. 作為最后的安全步驟,請確保從內存中刪除解密的密碼。

*有很多簡單的加密庫可供您對密碼進行加密。 微軟的數據保護API值得考慮。 請記住,如果有人可以訪問您的應用程序,則不可能實現完美的安全性。 您所能做的最好的事情就是添加混淆層,使黑客更難破解您的數據庫登錄憑據。

一些示例代碼

procedure TAbc.HandleOnLogin(Sender: TObject; Username, Password: string);
var
  LPassword: string;
begin
  LPassword := GetDecryptedPassword; //Your choice how you do this
  Connection.Open(Username, LPassword);
  //The next line ensures memory is erased before it is deallocated
  //which would otherwise leave the password hanging around.
  SecureZeroMemory(Pointer(LPassword), Length(LPassword) * SizeOf(Char));
end;

除了其他答案,您可以執行的操作是除去讀取進程內存的權限,這在控制用戶權限(例如在企業環境中)時很有用。

在過程開始時調用以下過程可防止非管理員用戶讀取過程內存。 (對於缺少的API調用,您將需要JEDI API單元)

uses JwaWinNT, JwaWinBase, JwaAclApi, JwaAccCtrl;

//...
{$SCOPEDENUMS ON}
function ProtectProcess(): DWORD;
type
  TSidType = (Everyone, CurrentUser, System, Admin);
var
  // Released on exit
  ProcessToken: THandle;
  TokenInfo: PVOID;

  SidCurUser: PSID;
  SidEveryone: PSID;
  SidSystem: PSID;
  SidAdmins: PSID;

  ACL: PACL;
  SecDesc: PSECURITY_DESCRIPTOR;
  Size: DWORD;
  TokenSize: DWORD;
  BResult: Bool;

  SIDAuthEveryone: SID_IDENTIFIER_AUTHORITY;
  SIDAuthSystem: SID_IDENTIFIER_AUTHORITY;
  SIDAuthAdministrators: SID_IDENTIFIER_AUTHORITY;

  SIDArray: array[TSidType] of PSID;
  I: TSidType;
const
  // Mimic Protected Process
  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684880%28v=vs.85%29.aspx
  // Protected processes allow PROCESS_TERMINATE, which is
  // probably not appropriate for high integrity software.
  DeniedPermissions =
            {READ_CONTROL |}
            WRITE_DAC or WRITE_OWNER or
            PROCESS_CREATE_PROCESS or PROCESS_CREATE_THREAD or
//            PROCESS_DUP_HANDLE or // this permission is needed for printing
            PROCESS_QUERY_INFORMATION or
            PROCESS_SET_QUOTA or PROCESS_SET_INFORMATION or
            PROCESS_VM_OPERATION or
            PROCESS_VM_READ or PROCESS_VM_WRITE
            // In addition to protected process
//            or PROCESS_SUSPEND_RESUME or PROCESS_TERMINATE
            ;
  // Standard and specific rights not explicitly denied
  AllowedPermissions = ((not DeniedPermissions) and $1FFF) or PROCESS_TERMINATE or SYNCHRONIZE;
begin
  ACL := nil;
  TokenInfo := nil;
  SecDesc := nil;
  try
    TokenSize := 0;
    ProcessToken := 0;
    // If this fails, you can try to fallback to OpenThreadToken
    if (not OpenProcessToken(GetCurrentProcess(), TOKEN_READ, ProcessToken)) then
    begin
      Result := GetLastError();
      Exit;
    end;

    BResult := GetTokenInformation(ProcessToken, TokenUser, nil, 0, TokenSize);
    Result := GetLastError();
    Assert((not BResult) and (ERROR_INSUFFICIENT_BUFFER = Result));
    if(not ((BResult = FALSE) and (ERROR_INSUFFICIENT_BUFFER = Result))) then
    begin
      // failed;
      Exit;
    end;

    if (TokenSize > 0) then
    begin
      TokenInfo := HeapAlloc(GetProcessHeap(), 0, TokenSize);
      Result := GetLastError();
      Assert(Assigned(TokenInfo));
      if (nil = TokenInfo) then
      begin
        // failed;
        Exit;
      end;
    end;

    BResult := GetTokenInformation(ProcessToken, TokenUser, TokenInfo, TokenSize, TokenSize);
    Result := GetLastError();
    Assert(BResult and Assigned(TokenInfo));
    if not (BResult and Assigned(TokenInfo)) then
    begin
      Exit;
    end;

    SidCurUser := (PTokenUser(TokenInfo)).User.Sid;

    SIDAuthEveryone := SECURITY_WORLD_SID_AUTHORITY;
    BResult := AllocateAndInitializeSid(@SIDAuthEveryone, 1,
        SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, SidEveryone);
    Result := GetLastError();
    Assert(BResult and Assigned(SidEveryone));
    if not (BResult and Assigned(SidEveryone)) then
    begin
      Exit;
    end;

    SIDAuthSystem := SECURITY_NT_AUTHORITY;
    BResult := AllocateAndInitializeSid(@SIDAuthSystem, 1,
        SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, SidSystem);
    Result := GetLastError();
    Assert(BResult and Assigned(SidSystem));
    if not (BResult and Assigned(SidSystem)) then
    begin
      Exit;
    end;

    SIDAuthAdministrators := SECURITY_NT_AUTHORITY;
    BResult := AllocateAndInitializeSid(@SIDAuthAdministrators, 2,
        SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
        0, 0, 0, 0, 0, 0, SidAdmins);
    Result := GetLastError();
    Assert(BResult and Assigned(SidAdmins));
    if not (BResult and Assigned(SidAdmins)) then
    begin
      Exit;
    end;

    SIDArray[TSidType.Everyone] := SidEveryone;   // Deny most rights to everyone
    SIDArray[TSidType.CurrentUser] := SidCurUser; // Allow what was not denied
    SIDArray[TSidType.System] := SidSystem;       // Full control
    SIDArray[TSidType.Admin] := SidAdmins;        // Full control

    // Determine required size of the ACL
    Size := SizeOf(ACL);

    // First the DENY, then the ALLOW
    Size := Size + GetLengthSid(SIDArray[TSidType.Everyone]);
    Size := Size + SizeOf(ACCESS_DENIED_ACE) - SizeOf(DWORD);

    for I := TSidType.CurrentUser to High(SIDArray) do
    begin
      // DWORD is the SidStart field, which is not used for absolute format
      Size := Size + GetLengthSid(SIDArray[I]);
      Size := Size + SizeOf(ACCESS_ALLOWED_ACE) - SizeOf(DWORD);
    end;

    Size := Size + SizeOf(DWORD);

    ACL := PACL(HeapAlloc(GetProcessHeap(), 0, Size));
    Result := GetLastError();
    Assert(Assigned(ACL));
    if not Assigned(ACL) then
    begin
      Exit;
    end;

    BResult := InitializeAcl(ACL, Size, ACL_REVISION);
    Result := GetLastError();
    Assert(BResult);
    if not BResult then
    begin
      Exit;
    end;

    BResult := AddAccessDeniedAce(ACL, ACL_REVISION, DeniedPermissions,
      SIDArray[TSidType.Everyone]);
    Result := GetLastError();
    Assert(BResult);
    if not BResult then
    begin
      Exit;
    end;

    BResult := AddAccessAllowedAce(ACL, ACL_REVISION, AllowedPermissions,
      SIDArray[TSidType.CurrentUser]);
    Result := GetLastError();
    Assert(BResult);
    if not BResult then
    begin
      Exit;
    end;

    // Because of ACE ordering, System will effectively have dwAllowed even
    // though the ACE specifies PROCESS_ALL_ACCESS (unless software uses
    // SeDebugPrivilege or SeTcbName and increases access).
    // As an exercise, check behavior of tools such as Process Explorer under XP,
    // Vista, and above. Vista and above should exhibit slightly different behavior
    // due to Restricted tokens.
    BResult := AddAccessAllowedAce(ACL, ACL_REVISION, PROCESS_ALL_ACCESS,
      SIDArray[TSidType.System]);
    Result := GetLastError();
    Assert(BResult);
    if not BResult then
    begin
      Exit;
    end;

    // Because of ACE ordering, Administrators will effectively have dwAllowed
    // even though the ACE specifies PROCESS_ALL_ACCESS (unless the Administrator
    // invokes 'discretionary security' by taking ownership and increasing access).
    // As an exercise, check behavior of tools such as Process Explorer under XP,
    // Vista, and above. Vista and above should exhibit slightly different behavior
    // due to Restricted tokens.
    BResult := AddAccessAllowedAce(ACL, ACL_REVISION, PROCESS_ALL_ACCESS, SIDArray[TSidType.Admin]);
    Result := GetLastError();
    Assert(BResult);
    if not BResult then
    begin
      SiMain.LogWin32Error('AddAccessAllowedAce failed: ', Result);
      Exit;
    end;

    SecDesc := PSECURITY_DESCRIPTOR(HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH));
    Result := GetLastError();
    Assert(Assigned(SecDesc));
    if not Assigned(SecDesc) then
    begin
      Exit;
    end;

    // InitializeSecurityDescriptor initializes a security descriptor in
    // absolute format, rather than self-relative format. See
    // http://msdn.microsoft.com/en-us/library/aa378863(VS.85).aspx
    BResult := InitializeSecurityDescriptor(SecDesc, SECURITY_DESCRIPTOR_REVISION);
    Result := GetLastError();
    Assert(BResult);
    if not BResult then
    begin
      Exit;
    end;

    BResult := SetSecurityDescriptorDacl(SecDesc, TRUE, ACL, FALSE);
    Result := GetLastError();
    Assert(BResult);
    if not BResult then
    begin
      Exit;
    end;

    SetSecurityInfo(
        GetCurrentProcess(),
        SE_KERNEL_OBJECT, // process object
        OWNER_SECURITY_INFORMATION or DACL_SECURITY_INFORMATION,
        SidCurUser, // Owner SID
        nil, // Group SID
        ACL,
        nil // SACL
        );
    Result := GetLastError();
    Assert(ERROR_SUCCESS = Result);
  finally
    if (nil <> SecDesc) then
    begin
      HeapFree(GetProcessHeap(), 0, SecDesc);
    end;
    if (nil <> ACL) then
    begin
      HeapFree(GetProcessHeap(), 0, ACL);
    end;
    if (SidAdmins <> nil) then
    begin
      FreeSid(SidAdmins);
    end;
    if (SidSystem <> nil) then
    begin
      FreeSid(SidSystem);
    end;
    if (SidEveryone <> nil) then
    begin
      FreeSid(SidEveryone);
    end;
    if (nil <> TokenInfo) then
    begin
      HeapFree(GetProcessHeap(), 0, TokenInfo);
    end;
    if (0 <> ProcessToken) then
    begin
      CloseHandle(ProcessToken);
    end;
  end;
end;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM