I use MySQL in a shared server account and my worry is if a hacker monitors the connection between my application and that MySQL server.
Is that connection ciphered anyhow or is it raw data passing through (including at the connection time when Zeos TZConnection component informs the server what is the data base name, user name and password)?
If it's raw, how could I add some protection to it?
Actually it is not your TZConnection which speaks with the server. Instead, it communicates with libmysql.dll which sends and receives data from the Mysql server.
To secure your connection to the server you can use SSL. You will need 3 certificates:
CA-cert.pem
client-cert.pem
client-key.pem
You can find information on how to generate them in this MySQL link.
Once you have them you need to setup TZConnection to indicate SSLshould be used as follows:
Connection.Properties.Values['MYSQL_SSL'] := 'TRUE';
Connection.Properties.Values['MYSQL_SSL_CA'] := 'c:/MyPath/CA-cert.pem';
Connection.Properties.Values['MYSQL_SSL_CERT'] := 'c:/MyPath/client-cert.pem';
Connection.Properties.Values['MYSQL_SSL_KEY'] := 'c:/MyPath/client-key.pem';
More information about MySql and SSL can be found in this discussion in Zeos forums.
Related
I am working with D5 ( thats a fact ). I have Indy9 installed.
I'm trying to receive data of IdMappedPortTCP on port 8041 (SSL) and redirect the data to a Tserversocket on port 8040. So I will have support of SSL over Tserversocket.
I use the following code:
var
masterdir:String;
begin
masterdir:=Extractfilepath(paramstr(0));
IdMappedPortTCP1.Active:=false;
datamodule2.IdMappedPortTCP1.MappedHost:='192.168.0.3';
datamodule2.IdMappedPortTCP1.MappedPort:=8041;
datamodule2.IdMappedPortTCP1.DefaultPort:=8040;
IdServerIOHandlerSSL1.SSLOptions.RootCertFile:=masterdir+'mycert.pem';
IdServerIOHandlerSSL1.SSLOptions.CertFile:=masterdir+'mycert.pem';
IdServerIOHandlerSSL1.SSLOptions.KeyFile:=masterdir+'key.pem';
IdMappedPortTCP1.IOHandler:=IdServerIOHandlerSSL1;
IdMappedPortTCP1.Active:=true;
end;
If I don't use SSL everything is fine. But when I use SSL teh request never comes to the port 8040 encrypted and I need it not encrypted so I can proccess it.
It is not clear from your description whether TServerSocket is using SSL on port 8040 or not. It makes a big difference in how you set up TIdMappedPortTCP. However, from your description, you have the MappedPort and DefaultPort property assignments backwards, at least. DefaultPort is the port that TIdMappedPortTCP listens on, so it should be 8041. MappedPort is the port that TIdMappedPortTCP connects to, so it should be 8040.
It is not common to have unencrypted and encrypted connections on the same port. Most protocols use separate ports. Is that the case here? Is port 8040 unencrypted, and port 8041 encrypted?
If you want TIdMappedPortTCP to accept encrypted and unencrypted clients on separate ports, you need to add 2 entries to the TIdMappedPortTCP.Bindings collection, one for each port, and not use the DefaultPort property at all. In the TIdMappedPortTCP.OnConnect event, you can detect which port the client connected to, and then configure the AThread.OutboundClient accordingly before it connects to TServerSocket.
It is not wise to have unencrypted and encrypted clients connect to the same port. In that scenario, you have to sniff the first few bytes to know if the client is sending an SSL handshake or not, and then act accordingly. It is easier to just use separate ports instead. However, some protocols do allow a client to connect to an unencrypted port and then send a command to activate encryption when needed. In that scenario, you would only need 1 port in TIdMappedPortTCP, so you can either define 1 Binding or use DefaultPort.
TIdMappedPortTCP is primarily intended to be a straight passthrough of raw bytes back and forth between the client and the target server. If TServerSocket is using SSL and you want the client to talk to TServerSocket using SSL properly, you should not be using TIdServerIOHandlerSSL at all. Let TIdMappedPortTCP pass the client's raw encrypted data as-is to TServerSocket, and vice versa. They should establish a secure session with each other, not with you. This is especially important if either one of them performs peer identity validation.
If you need to process encrypted data that is being exchanged between the client and TServerSocket, you have to decrypt and re-encrypt the data as it passes through TIdMappedPortTCP (which means you are acting as a man-in-the-middle attacker, which peer validation is meant to prevent). To do that, you have to establish separate SSL sessions between the client and TIdMappedPortTCP, and between TIdMappedPortTCP and TServerSocket. Assigning a TIdServerIOHandlerSSL to TIdMappedPortTCP only facilitates the session with the client. You have to manually setup a session with TServerSocket. To do that, you have to manually assign a new TIdSSLIOHandlerSocket object to the AThread.OutboundClient.IOHandler property in the OnConnect event. TIdMappedPortTCP will not handle that for you.
If, however, TServerSocket is not using SSL, and you are using TIdMappedPortTCP as an SSL gateway into TServerSocket, then you can skip the OutboundClient.IOHandler assignment, since you would only need 1 SSL session, between TIdMappedPortTCP and the client.
Now, with that said, there are some problems in Indy 9. The TIdSSLIOHandlerOpenSSL.PassThrough property is False by default (thus assuming encryption is initially active), and TIdServerIOHandlerSSL assumes that every accepted client connection is using SSL, even if it really is not. If an unencrypted client connects to TIdMappedPortTCP with TIdServerIOHandlerSSL assigned, the client will not be handled correctly. These issues were fixed in Indy 10. But in Indy 9, you will not be able to handle encrypted and unencrypted clients in the same TIdMappedPortTCP component. If you are only dealing with encrypted clients though, you won't run into a problem. Otherwise, create 2 TIdMappedPortTCP components, one listening on an unencrypted port, the other listening on an encrypted port. They can share the same event handlers. If needed, you can use the AThread.Connection.Socket.Binding.Port property to know which port the client is connected to.
I'm using code from a demo program using Devart's MyDac component using Delphi 2009 to connect to a remote database using SSL.
I have made and verified the certificates and keys and set the connection parameters in MyDAC to use them eg
MyConnection.protocol := 'mpSSL';
MyConnection.SSLOptions.CACert := 'C:\ca-cert.pem';
MyConnection.SSLOptions.Cert := 'C:\client-cert.pem';
MyConnection.SSLOptions.Key := 'C:\client-key.pem';
MyConnection.SSLOptions.Chipherlist := 'All';
When I tell MyConnection to connect (after setting the user name / password etc) it connects to the database with no problems.
However as a test I deliberately put in an invalid key name of 'C:\XXXclient-key.pem and it still connected OK so maybe it wasn't using SSL at all.
So my question is:
How can I use Delphi to detect if a connection is really using SSL or not?
I think I'll close this question myself as it seem far more complex than I thought it was and I need much more information before this question makes sense. It appears that the sql statement;
SHOW STATUS LIKE 'Ssl_cipher'
can help as its value will be empty if its not using ssl or will contain an value if it is.
The touble was the Mysql server I was using (ISP Nativespace) did not even have a variable name called Ssl_cipher so it looks like it doesn't support ssl anyway. Trying the same thing using another ISP I did see the variable name but it had no value, showing that was also not using ssl even I though it could do it.
It now appears that there is much more that needs doing before a ssl connection can be set up. Creating a new user on the db that only ever uses ssl, setting up permissions for them, running code on the server etc.
Not at all as simple as Devart's web page on securebridge leads one to believe!
"It is enough to place several components on the form and specify the
server address and the user login information to establish a secure
connection."
Err... not quite!
I've written a small application using delphi to update my twitter status.
I use Indy 10 and OpenSSL and everything works fine, which means that i can both authenticate my app and update my status.
The thing is that if i use a program like "http analyzer" i can see the request's headers and so i can see sensitive information like the consumer_key.
Is that normal or is it a sign that i have not set properly the iohandler (TIdSSLIOHandlerSocketOpenSSL)?
mSslIoHandler.SSLOptions.Method := sslvSSLv3;
mSslIoHandler.SSLOptions.Mode := sslmBoth;
mSslIoHandler.SSLOptions.VerifyMode := [];
mSslIoHandler.SSLOptions.VerifyDepth := 0;
By providing their own SSL certificates, HTTP analyzers are able to monitor the HTTP traffic as if it was unencrypted. I guess you have to set the analyzer IP address and port as proxy only, and leave the destination server address and port unchanged in the client. Then the analyzer will be able to decrypt your client data with its own key, and forwards it to the destination server. (This is the same way a 'man in the middle'-attack would work)
So yes, it is normall with this type of HTTP analyzers (such as Fiddler)
Using Delphi XE to build a relatively straightforward database app using Datasnap.
Since some security in my application is handled at the database level, I need to pass a user's SQL credentials from my client app to my Datasnap server.
(I'm trying to make the Datasnap server stateless if possible, so recognise that I will have to do this for every call.)
I'm using ClientDatasets (CDS) on the client side so I could use OnBeforeGetRecords to pass the data in the OwnerData OleVariant from the CDS on the client to the corresponding TDataSetProvider on the server. But that means every single CDS on every data module has to have an event that does this, which seems messy and unwieldy. I can't help feeling there must be a way to pass messages to the server at a higher level than that.
What I'd really like is something like this at the DSServerClass level on the server side:
Procedure TMyServerContainer.MyServerClassCreateInstance(DSCreateInstanceEventObject: TDSCreateInstanceEventObject);
begin
// Server detects request for data from client app
fUsername := GetUsernameFromClientSomehow;
fPassword := GetPasswordFromClientSomehow;
// create data modules and initialise
MyDataModule := TMyDataModule.Create(nil);
MyDataModule.InitialiseWithSQLCredentials(fUsername, fPassword);
DSCreateInstanceEventObject.ServerClassInstance := MyDataModule;
End;
Could the Authentication Manager component help me here? Any other ideas? Or am I stuck with OnBeforeGetRecords?
Many thanks.
You can use the SQL credentials as UserName and Password for connecting to the DataSnap server. These values can be verified in the Authentication Manager and/or simply forwarded to the underlying SQLConnection component for connecting to the SQL server.
The most secure way would be to pass along the user security token (encrypted) and then use integrated security on the server side impersonating in a thread the calling user security context. This way no user/password would ever be sent across the wire. Unluckily while MS/DCE RPC can do this for every call (and DCOM, being built above RPC), Datasnap can't (SPNEGO/GSSAPI/SSPI looks to complex for the guys at Embarcadero, they like simple, unsecure protocols). Otherwise be very careful the way you send credential across the network, they could be easily sniffed unless properly protected.
I would advise you anyway to send them only once, if you need to (and in the most protected way you can), and then store them protected on the server side (suing Windows protected storage facilities), and send back to the client an handle/session token (tied to the originating IP), to be used in subsequent calls instead of resending credentials each time. Informations are cleared when the user logs off or the session timeouts.
How can Indy's TIdTCPClient and TIdTCPServer be used in the following scenario:
Client ---------- initate connection -----------> Server
...
Client <---------------command------------------- Server
Client ----------------response-----------------> Server
...
Client <---------------command------------------- Server
Client ----------------response-----------------> Server
The client initiates the connection, but acts as a "server" (waiting for commands and executing them).
The OnExecute approach of TIdTCPServer does not work well in this case (at least I am not getting it to work well). How could I do this?
I hope the question is clear enough.
There is nothing preventing you from doing this with Indy's TIdTCPServer component.
A TIdTCPServer only sets up the connection. You'll need to implement the rest. So the sequence of the actual sending and receiving can be whatever you want.
Put this code in your TIdTCPServer component's OnExecute event:
var
sName: String;
begin
// Send command to client immediately after connection
AContext.Connection.Socket.WriteLn('What is your name?');
// Receive response from client
sName := AContext.Connection.Socket.ReadLn;
// Send a response to the client
AContext.Connection.Socket.WriteLn('Hello, ' + sName + '.');
AContext.Connection.Socket.WriteLn('Would you like to play a game?');
// We're done with our session
AContext.Connection.Disconnect;
end;
Here's how you can setup the TIdTCPServer really simply:
IdTCPServer1.Bindings.Clear;
IdTCPServer1.Bindings.Add.SetBinding('127.0.0.1', 8080);
IdTCPServer1.Active := True;
This tells the server to listen on the loopback address only, at port 8080. This prevents anyone outside of your computer from connecting to it.
Then, to connect your client, you can go to a Windows command prompt and type the following:
telnet 127.0.0.1 8080
Here's the output:
What is your name?
Marcus
Hello, Marcus.
Would you like to play a game?
Connection to host lost.
Don't have telnet? Here's how to install telnet client on Vista and 7.
Or with a TIdTCP Client, you can do this:
var
sPrompt: String;
sResponse: String;
begin
// Set port to connect to
IdTCPClient1.Port := 8080;
// Set host to connect to
IdTCPClient1.Host := '127.0.0.1';
// Now actually connect
IdTCPClient1.Connect;
// Read the prompt text from the server
sPrompt := IdTCPClient1.Socket.ReadLn;
// Show it to the user and ask the user to respond
sResponse := InputBox('Prompt', sPrompt, '');
// Send user's response back to server
IdTCPClient1.Socket.WriteLn(sResponse);
// Show the user the server's final message
ShowMessage(IdTCPClient1.Socket.AllData);
end;
An important thing to note here is that the ReadLn statements wait until there is data. That's the magic behind it all.
If your commands are textual in nature, then have a look at the TIdCmdTCPClient component, it is specifically designed for situations when the server is sending commands instead of the client. The server can use TIdContext.Connection.IOHandler.WriteLn() or TIdContext.Connection.IOHandler.SendCmd() to send the commands.
When the client connects to the server, the server has an OnConnect event with an AContext: TIdContext parameter.
A property of this is AContext.Connection, which you can store outside of that event (say, in an Array). If you pair it with the IP or better yet a generated Session ID, then reference that Connection by that criteria, you can then have the server send adhoc commands or messages to the client.
Hope this helps!
normally the client and the server side have a thread that is reading incoming telegrams, and sending pending telegrams...but this kind of protocols (send/receive, when and what) depend of the application.
A very good starting point how the client side can be implemented using a thread, listening for messages from the server, is the Indy Telnet client component (TIdTelnet in the Protocols folder).
The Indy telnet client connects to the telnet server and uses only one socket to write and read data. Reading happens in a listener thread.
This design can easily be adapted to build distributed messaging software like chat etc., and also shows how easy the protocol can be decoupled from the network layer using blocking sockets.
With Indy this is not possible by design:
Indy supports only Client-initiated communication, what means the server can only send a response to requests by the client.
The easiest way (but not the smartest) to get what you want is to use a pull-process. Controlled by a timer the clients ask the server if there is a new command. Of course this will cause a lot of traffic-overhead and depending on your pull-intervall there is a delay.
Alternatively you could use another library like ICS (http://www.overbyte.be/eng/products/ics.html)