How to secure your communication

Security is a problem

Most of the real-world applications process some sensitive business-critical information. And sometimes the theft of this information could lead to disastrous consequences for businesses.

IT security measures become one of the most important parts of modern IT infrastructure. And surprisingly, the most important part of it is neither equipment nor software - it is people. I suggest you to read the excellent book IT Security: Risking the Corporation written by Linda McCarthy if you want to know some more about IT security in general.

In this article we will discuss ways how one can build secure application based on Remoting SDK services. We will only touch this theme, but it should be enough to see the picture in general. After reading this article, you'll be able to select ways appropriable particularly for you to build new secure applications or to enforce security in already existing ones.

We will discuss some general things about user rights management, about login services and about traffic encryption.

Network security

At first your server application's host should be secure, because you cannot build a castle on the sand.

We will not cover questions of network security in this article - this is too far beyond its scope. But you must remember that there is no sense to build some complex user management system with complex data access rules based on user's business roles, when someone can simply steal the entire database due to a misconfigured internet firewall.

User rights management

User input validation

You should never rely on the client side for client input validation. You should always expect that data your server application receives from clients is tampered with or just invalid. This can be due to malice or no more than network failure, but it is up to you to filter out such data.

You should always use parameterized SQL queries instead of combining query strings from templates like 'SELECT user_id FROM USERS WHERE user_name=' and user provided input.

This rule seems obvious, but it is violated too often. I suggest you to read specialized articles about SQL Injection and Buffer Overflow attacks and its prevention if you want to know more.

The Data Abstract framework has already implemented features that allow you to make your server application more secure.

First of all is the Dynamic Where feature, which could be used to allow client application to query data filtered by some condition. Using this feature could prevent SQL Injection attacks because Dynamic Where always uses SQL Parameter mechanism and prevents using in the where conditions database fields which are not exposed in the DataAbstract Schema.

Also there are several properties of the DataAbstract service that could be used to manage security aspects of DataAbstract server applications:

By default these properties are set to False to prevent abuse of server application. Turn these features on only if they are used by your client application.

User rights management

In most modern applications, GUI prevents users from doing inappropriate actions. But again this restriction can be overridden. There are utilities, even freeware, which can easily enable disabled or hidden buttons etc. Your server app should always double check if this particular action allowed to this particular user.

Data access management

Most of the modern databases have decent user rights management. You could use them to somehow setup data access for these users. Another way is to restrict user access at server app level. Usually it is done this way:

  • Client application connects to server one and provides come credentials (login/password, see below.)
  • Client application requests some data (i.e. some report).
  • Server application checks using some business rules if this is user allowed to request data.
  • If the user is not allowed, server app returns some signal to the client, that request is denied and (optionally) logs denied request.
  • If the request is allowed, server application logs into the database using his own credentials (which should be unknown to the users), gathers data, processes it and returns it to the client application

Using this approach you can flexibly setup user access rights. Not surprisingly, the main drawback of this approach is the same - it is up to you to create some system to manage user's access rights.

Note: In RemObjects DataAbstract framework a Business Rules Scripting API component is present, which can be used for business rules enforcement. See the sample for .NET or Delphi.


Login services

In IT security, login (logging or signing in) is the process by which individuals access a computer system, that is controlled by identification of user credentials provided by the user. A user can log into a system to obtain access, and then log out when the access is no longer needed.

Usually data-driven applications give limited view-only access to a subset of data stored or no access at all, until user is logged in. Logout is usually performed when quitting the application.

In most cases user credentials consist of user name and a secret user password, but some systems store user credentials on secure storage devices like HASP.

To implement login and logout functionality using the Remoting SDK framework, you should define a new service with two methods named LogIn and LogOut. There you should implement some functionality of user credentials check etc. LogIn method in most simple cases returns only a Boolean flag if access is granted or not. More sophisticated LogIn implementations could also return some structure containing user information (i.e. user's full name, department etc).

RemObjects DataAbstract makes LogIn implementation much easier. You should add to your server app's .RODL a new service which inherits SimpleLoginService. In this newly added service you should implement event handlers for events OnLogin and OnLogout (for Delphi) or ExecuteLogin (for .NET).

You could check DAServer (for DataAbstract Delphi) or SampleServer (for DataAbstract .NET) to see Login service in action. You can also create your own DataAbstract application based on standard Data Abstract template and try to implement login service by yourself.

Note that DataAbstract Login Service uses sessions mechanism described in another article. You could utilize sessions to store user related information including user access rights.

Also IMultiDbLoginService is offered, that allows you to easily handle logins to different databases. Application templates using this service are shipped with the DataAbstract framework.


Traffic encryption

Another security threat is network traffic interception, especially when server and client applications communicate over Internet. One can intercept information sent over the network and steal data or even user credentials. The only way to prevent this is network traffic encryption.

User implemented encryption

The most obvious way of implementing encryption is to implement encrypting and decrypting routines by yourself. But this approach can take too many efforts because you'll not only need to implement cryptographic routines, but also to call these routines in every client application's procedure that calls remote server application and in every server application's procedure that uses any client provided parameters or sends data to a client.

Remoting SDK provides two other ways of network traffic encryption. Both of them are easy to implement and are fully transparent for server and client applications. They are Delphi encrypted channels and message envelopes.

Delphi encrypted channels (deprecated)

The main drawback of this technology is that it is Delphi specific. Due to architectural differences it is impossible to create compatible channels on the .NET side. So you should consider usaging encrypted channels as option only if you have already developed an application and do not plan to communicate with .NET-based applications. In all other cases you should use AES message envelopes (see below).

If your server and client applications are both Delphi-based, all you need to enable network traffic encryption is:

  • At server side:
    • Set server channel's Encryption.EncryptionMethod property to one of the following values: tetDES, tetBlowfish, tetTwoFish, tetRijndael (see below). So you can select one of available cryptographic algorithms.
    • Provide encryption and decryption keys by setting properties Encryption.EncryptionSendKey and Encryption.EncryptionRcvKey
  • At client side:
    • Set client channel's properties Encryption.EncryptionMethod, Encryption.EncryptionSendKey and Encryption.EncryptionRcvKey to same values as corresponding server channel's properties.
Enumeration value Cryptographic algorithm
tetNone No encryption as applied
tetDES Triple DES
tetBlowfish Blowfish
tetTwoFish Twofish
tetRijndael Rijndael (also known as AES encryption algorithm)

Implementation of these algorithms in RemObject SDK is based on Hagen Reddmann's Delphi Encryption Compendium.

You can see encryption channels in action in MegaDemo Sample (.NET) or MegaDemo Sample (Delphi). The encryption channels can be turned on or off using Encrypt communication checkboxes.

AES Envelope

Envelopes are a brand new mechanism that allows applications to modify data packets right before they will be sent over the network or immediately before or after they were received. So it is an ideal mechanism to add transparent encryption to RemObject SDK applications.

Envelopes will work with any message type, although they will not be conforming to SOAP or XML-RPC standards (for obvious reasons). AES Envelope is an encryption envelope that is shipped with the Remoting SDK. It uses AES encryption to encrypt and decrypt messages. Its encryption key is generated based on Password property.


What is AES?
According to Wikipedia, the Advanced Encryption Standard (AES) is an encryption standard adopted by the U.S. government. The standard comprises three block ciphers, AES-128, AES-192 and AES-256, adopted from a larger collection originally published as Rijndael. Each AES cipher has a 128 bit block size, with key sizes of 128, 192 and 256 bits, respectively. The AES ciphers have been analyzed extensively and are now used worldwide.


Envelopes could be added to the message's Envelopes property.

Note that envelopes could be enabled or disabled using Enabled property, but even if an envelope's Enabled property is set to false, but this envelope type is needed to process incoming messages, it will be used. AES Envelope's Password could be set at any time = you don't have to restart the server or to reconnect to it to change the AES password.

You can see an extensive sample of AES Envelope usage in MegaDemo Sample (.NET). In MegaDemo Sample (Delphi) usage, AES Envelope is triggered by the Use message envelopes checkbox and in .NET one by the Use AES Encryption Envelope checkbox.

Performance and security trade-off

You may notice when using the MegaDemo Sample (Delphi), that enabling AES encryption envelopes results in some performance loss. This performance loss depends on the amount of data transferred and usually it is no more than 5 percent of initial performance with encryption disabled.

In most cases this is reasonable trade-off between performance and security. But if your applications design doesn't need such secure encryption or vise versa it needs even more secure encryption you can implement your own message envelope.

Implementing your own Message Envelope

Detailed step-by-step tutorial regarding Message Envelopes implementation is beyond the scope of this article and will be presented in another one.

This section contains only common overview how you can implement Envelopes and some general recommendations.

To create an Envelope you must inherit a class from the MessageEnvelope class (TROMessageEnvelope in Delphi) is located in RemObjects.SDK.MessageEnvelope or uROClient.pas (Delphi). In these code snippets, the newly defined class is named TXOREncryptionEnvelope or XorEncryptionEnvelope in Delphi and C# code snippets accordingly.

TXOREncryptionEnvelope = class(TROMessageEnvelope)
private
  fPassword: string;
protected
  procedure intProcessIncoming(Source, Dest: TStream; aMessage: IROMessage); override;
  procedure intProcessOutgoing(Source, Dest: TStream; aMessage: IROMessage); override;

  function GetDefaultEnvelopeMarker: string; override;
public
  constructor Create(aOwner: TComponent); override;
  property Password: string read fPassword write fPassword;
end;
public class XorEncryptionEnvelope : MessageEnvelope
{
    // Fields
    private String fPassword;

    // Methods
    public XorEncryptionEnvelope();

    protected override void DoUnwrap(Stream source, Stream destination);
    protected override void DoWrap(Stream source, Stream destination);

    // Properties
    public override String DefaultEnvelopeMarker { get; }
    public String Password { get; set; }
}

DefaultEnvelopeMarker is used to determine which envelope should be called to process incoming messages. Another functions (intProcessIncoming and intProcessOutgoing or DoUnwrap and DoWrap) is used to decrypt or encrypt messages accordingly. Note that these functions should be thread safe, have no memory leaks and have the fastest implementation possible.


Summary

It this article we discussed some security threats and according security countermeasures. This article shows how to utilize AES traffic encryption transparently for both server and client applications to prevent traffic interception. Basics of custom envelopes creation were also described.