[英]Protect Delphi Connection String From Hack
您沒有使用資源黑客。 如果您的字符串存儲在資源中,它們將更易於查找和查看。
相反,您使用的是內存掃描程序,它可以在程序運行時查看程序的原始內存。 最終,您必須在內存中創建一個連接字符串才能傳遞給數據庫引擎。 如果黑客可以訪問應用程序及其內存,則他們可以使用其數據的應用程序。 具有這種訪問權限的專門黑客將能夠在使用該字符串時搶劫該字符串。
但是您可以采取一些措施,使休閑黑客更難。
一方面,禁止非管理員用戶訪問您的應用。 當用戶運行掃描儀應用程序時,它可能有權訪問由同一用戶運行的其他應用程序中的內存。 在不同的用戶上下文或提升的流程中運行您的應用程序。 用戶運行的應用程序無法訪問其他用戶正在運行的其他應用程序的內存,除非他/她被明確授予他們許可,或者他/她是管理員。 如果黑客有權訪問您的應用程序,則所有選擇都將關閉。
另外,將字符串分成較小的子字符串,需要時可以將其串聯。 動態建立連接字符串。 這樣,如果黑客嘗試瀏覽磁盤上的EXE文件本身,子字符串就不會存儲在一個地方。
而且, 切勿將敏感的憑據存儲在以開頭的應用程序代碼中 。 將它們存儲在外部,並對其進行加密。 僅在絕對需要時才將它們檢索到內存中,並在使用SecureZeroMemory()
使用SecureZeroMemory()
安全銷毀該內存的內容。 如果您需要在內存中保留憑據或連接字符串超過幾毫秒,請在不積極使用內存時考慮使用CryptProtectMemory()
對內存進行加密。
將連接字符串拼湊起來需要花費的工作越多,一個隨意的黑客也將不得不做更多的工作。 但是,專門的黑客只會等到您完成所有工作后,才在使用它時從內存中拔出最后一個字符串,因此您必須盡一切努力防止訪問內存。
'Persist Security Info=False'
Connection.
LoginPrompt為True
。 Connection.Open
調用。 *有很多簡單的加密庫可供您對密碼進行加密。 微軟的數據保護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.