4

I have made a sample application in Delphi xe10 and make user id and password and database name encrypted and decrypt on connecting the problem is when I open exe process in memory by memory scanner I can find all of them easily by searching some part of the connection string is it such easy to find secure connection data in win applications or I did something wrong? connect enter image description here

kobik
  • 21,001
  • 4
  • 61
  • 121
dawood karimy
  • 179
  • 2
  • 13
  • 3
    Have you considered using OS Authentication, rather that Sql Server logins? – MartynA Dec 23 '17 at 11:23
  • i can't use windows authentication because we have to many connection from any untrusted domain's – dawood karimy Dec 23 '17 at 12:31
  • 2
    Inl that case, I'm a bit surprised you allow direct connections to your Sql Server at all. That situation cries out for a 3-tier solution, with the middle tied in a secure environment and access to the server only being allowed from the middle tier. – MartynA Dec 23 '17 at 12:36
  • i know that but this is and old product and we need some solution to secure our connection as it posible – dawood karimy Dec 23 '17 at 12:53
  • What happens if you chage connectionstring of adoconnection after connection succeed? – sddk Dec 23 '17 at 13:27
  • you can not change connection string when connection is open – dawood karimy Dec 23 '17 at 13:33
  • @sddk I don't understand what you mean by that. ADO components won't let you change connection string without disconnecting first. – Jerry Dodge Dec 23 '17 at 13:33
  • ok, i thought that memory scanner read that data via adoconnection – sddk Dec 23 '17 at 13:46
  • Good question. I would expected the `Persist Security Info=False` to not store this information in memory. BTW, which "memory scanner" did you use? – kobik Dec 24 '17 at 16:30
  • Persist Security Info=False exists in connection string and the memory scanner software is hxd https://mh-nexus.de/en/hxd/ – dawood karimy Dec 25 '17 at 07:00

3 Answers3

0

Don't put the password in the connection string. Instead assign an OnWillConnect event handler to TADOConnection and supply the password there in the supplied parameter.

Larsdk
  • 705
  • 6
  • 10
  • There is a possible problem with this: If you add the Connection's ConnectionString to a TMemo in the AfterConnect event, you'll see that the `UserID` (login name) is present in it. Worse, if the PersistSecurityInfo is set to True (in the IDE or e.g. by a hack of the app), the password will also appear in the memo. – MartynA Dec 23 '17 at 18:36
  • 1
    if you look the picture i attached there is not userid and password in connection string and i test onwillconnect parameters befor and results are same – dawood karimy Dec 24 '17 at 05:04
0

Try to protect the memory. Use CryptProtectMemory and CryptUnprotectMemory.

https://msdn.microsoft.com/de-de/library/windows/desktop/aa380262(v=vs.85).aspx

Here is an small snippet from my class. Play with it:

        uses
         Winapi.Windows,
          System.SysUtils;
        ....

TMyMemEncryptBlaBla = class
    private
    //......
     public
      function MemEncrypt(const StrInp: String; CryptFlags: DWORD = 0): TBytes;
      function MemDecrypt(const EncInp: TBytes; CryptFlags: DWORD = 0): String;
     end;

    {
 BOOL WINAPI CryptProtectMemory(_Inout_ LPVOID pData,
                                _In_    DWORD  cbData,
                                _In_    DWORD  dwFlags );

 }
function CryptProtectMemory(Data: Pointer; Size: DWORD; Flags: DWORD) : BOOL; stdcall;
 {
 BOOL WINAPI CryptUnprotectMemory(_Inout_ LPVOID pData,
                                  _In_    DWORD  cbData,
                                  _In_    DWORD  dwFlags );

 }

function CryptUnProtectMemory(Data: Pointer; Size : DWORD;Flags: DWORD) : BOOL; stdcall;

// CryptProtectMemory and CryptUnprotectMemory.

 CRYPTPROTECTMEMORY_SAME_PROCESS  = 0; // Set as default
 CRYPTPROTECTMEMORY_CROSS_PROCESS = 1;
 CRYPTPROTECTMEMORY_SAME_LOGON    = 2;
 CRYPTPROTECTMEMORY_BLOCK_SIZE = 16;

implementation

function CryptProtectMemory;  external 'Crypt32.dll' Name 'CryptProtectMemory';
function CryptUnProtectMemory; external 'Crypt32.dll' Name 'CryptUnprotectMemory';

// encrypt
function TMyMemEncryptBlaBla.MemEncrypt(const StrInp: String; CryptFlags: DWORD): TBytes;
begin
  Result := TEncoding.Unicode.GetBytes(StrInp);
  try
    if Length(Result) mod CRYPTPROTECTMEMORY_BLOCK_SIZE <> 0 then
      SetLength(Result, ((Length(Result) div CRYPTPROTECTMEMORY_BLOCK_SIZE) + 1) * CRYPTPROTECTMEMORY_BLOCK_SIZE);
  except
    on E:Exception do
     begin
      MessageBox(0, PChar(E.Message), PChar('E_OUTOFMEMORY'), MB_ICONERROR or MB_OK);
     end;
  end;
  try
     if not CryptProtectMemory(Result, Length(Result), CryptFlags) then
      begin
        MessageBox(0, PChar('MemCrypt: ' + SysErrorMessage(GetLastError)), PChar('MemEncrypt failed'), MB_ICONERROR or MB_OK);
        ZeroMemory(Result, Length(Result));
      end;
  except
    on E:Exception do
      begin
        MessageBox(0, PChar(E.Message), PChar('MemEncrypt Exception'), MB_ICONERROR or MB_OK);
      end;
  end;
end;
//decrypt
function TMyMemEncryptBlaBla.MemDecrypt(const EncInp: TBytes; CryptFlags: DWORD): String;
var
  DecTmp: TBytes;
begin
  DecTmp := Copy(EncInp);
  try
     if CryptUnprotectMemory(DecTmp, Length(DecTmp), CryptFlags) then
        Result := TEncoding.Unicode.GetString(DecTmp)
     else
        MessageBox(0, PChar('MemDecrypt: ' + SysErrorMessage(GetLastError)), PChar('MemDecrypt failed'), MB_ICONERROR or MB_OK);

      ZeroMemory(DecTmp, Length(DecTmp));
  except
    on E:Exception do
        MessageBox(0, PChar(E.Message), PChar('MemDecrypt Exception'), MB_ICONERROR or MB_OK);
  end;
end;

end.

Axel

Axel L.
  • 1
  • 2
  • The OP already has an encrypted password before the process is started. He then decrypt it when the process is running. How will he encrypt the password before the process started? from the documentation: "Do not use this function to save data that you want to decrypt later"... – kobik Dec 26 '17 at 16:36
  • i have not any problem with encrypt and decrypt string and my sample has this methods my problem is securing connection string when process is running – dawood karimy Dec 28 '17 at 08:28
  • To secure some strings in memory, try this [SecureString](https://medium.com/@svanas/creating-a-securestring-type-for-delphi-part-1-e7e78ed1807c) – Axel L. Dec 28 '17 at 16:42
0

Thinking out of box.... why you want hide password?

If database is on user's computer, Then he/she can open database simply by windows authentication mode using SQL management studio with out password!

If Database is on a remote server sure it is better to write a web service that fetch data and send result in XML for you program instead of remote opening database .

Shahram Banazadeh
  • 500
  • 1
  • 5
  • 15
  • hello shahram i told before this is and old large application and i never want to change structure of application – dawood karimy Dec 28 '17 at 08:20
  • I have some applications like this, I would never dare to think about changing structer. But I think in your situation the only soultion is this. Even if you hide password in memory , It can be sniffed . – Shahram Banazadeh Dec 28 '17 at 09:44
  • Theoretically , You have an other solution , is it possible to add a windows service to you old application?If yes then make local copy of Data base and write a windows servie that use a web service to sync local DB and main DB( remote one). No changes needed to your old applicaton.just making connection string local . – Shahram Banazadeh Dec 28 '17 at 09:52
  • this is very big change! it's not possible to create a windows service and localdb for every client and sync all client db to main server and all together – dawood karimy Dec 28 '17 at 09:57