EWD.js: Application, Web Service and REST Security

As soon as you venture into the world of browser-based and Web Services-based architectures, you quickly realise that, unless you think things through very carefully, it’s a potential security nightmare.  You’re exposing databases containing sensitive data to the equivalent of the Wild West: a multitude of people who are apparently hell-bent on causing havoc either for monetary gain or just because they can.  All you  have at your disposal is a minimal set of protocols (HTTP/HTTPS and Web Sockets), neither of which provide much, if anything, in the way of built-in security measures.  Indeed, in the case of HTTP and HTTPS, they’re pretty much wide open.  Of course the benefits of this world are many-fold and well understood to the extent that browser-based applications and Web Services are now recognised as the mainstream way of delivering applications.  So the trick is to find ways to realise those benefits for the users to whom you want to allow access whilst preventing unauthorised access by the Wild West.  It turns out that it is actually possible to put in place strong security measures.  The fact that we can safely do online shopping and banking on the open Internet tells you that security over the Web is a solvable problem.

A key raison d’etre of Web Application frameworks is to provide an automated and comprehensively-applied set of solutions to the issue of security.  The framework can look after security, leaving the developer to focus on the functionality of the application.  In this article I’d like to delve into the mechanisms provided by EWD.js for both browser-based applications and Web Services, and, for the latter, look at how this mechanism is harnessed by the EWD REST Server.

I’d like to thank Sidney Tarason for suggesting I write such an article.

How EWD.js Security Works for Browser-based Applications

In a browser-based application that is intended for use by only those people who are authorised to use it, the usual approach is that the user has to enter his/her authentication credentials: typically a username and password, though other, more sophisticated mechanisms such as two-factor authentication may be employed instead or as well as a username/password.

Once logged in, it is critical that every subsequent interaction between the user’s browser and the “back-end”  includes some kind of information that not only unequivocally identifies the authenticated user, but also is impossible (to all intents and purposes) to have been guessed by a member of the Wild West.

In EWD.js browser-based applications, all the dynamic interaction between the browser and “back-end” is conveyed as Web Socket messages that carry JSON-structured data payloads.  Each Web Socket message includes a developer-defined type, and each message type has a corresponding back-end handler function that processes that message appropriately.

Unlike the connectionless nature of HTTP/HTTPS, Web Sockets involve the creation of a TCP socket between the browser and “back-end” (in the case of EWD.js, that back-end being its master Node.js process).  The fact that such a persistent connection has been established between the two endpoints removes at least some of the possibilities for someone else using a browser or HTTP Client anywhere on the Internet to pretend to be an authenticated user.  However, it doesn’t remove all the risks and, no doubt, new exploits will be discovered over time.  In order to pre-empt such risks and to counter the remaining known ones, EWD.js does the following:

When the main “container” page (by convention usually named index.html) is loaded into the browser, a set of interactions occur behind the scenes whereby EWD.js establishes a back-end User Session, identified by a unique Session Id, and generates a random string known as a token which is sent to the browser over the newly-established Web Socket connection.  This process is known as registration.  Note that at this stage the user has not been logged in, so in theory anyone, including a member of the Wild West, could have loaded an EWD.js application’s container page and be registered with a token and back-end EWD.js Session.

The token provides an otherwise meaningless proxy to the back-end Session Id.  As it is a randomly-generated string, it can’t be guessed and can’t be decrypted into anything meaningful.  Every time an EWD.js application’s container page is requested, the token that is generated during registration will be different.

Whenever a Web Socket message is sent from the browser to the back-end, EWD.js intervenes and adds the token to its JSON payload.  If the back-end receives a Web Socket message containing a token that it recognises,  it can be confident that the sender is the same person whose application container page was originally registered.  The token then allows the incoming Web Socket message to be associated with the correct EWD.js User Session.

Furthermore, the token is used as a proxy to the application that was specified at the time of registration.  A tokenised message therefore prevents a user from trying to access message handlers for a different EWD.js application.

An error response or, in some cases no response results, if:

  • an incoming Web Socket message does not include a token;
  • EWD.js doesn’t recognise the token as one that it has registered;
  • the timeout period for the token has been exceeded.  Token timeouts are 1 hour by default, but the timeout can be set to any duration by the author of the application;
  • no back-end handler function exists for the message type specified in the Web Socket message.

Despite these measures, what you have to always remember is that no matter how much defensive JavaScript logic you have running within the user’s browser, much of what happens in the browser can be hi-jacked, examined and stepped through using the Developer Tools/JavaScript Console that are included with most modern browsers.

So how does EWD.js cope with the following obviously potentially dangerous situations:

  • a malicious user who has not yet logged in sending Web Socket messages, armed with a valid message type and a potentially dangerous JSON data payload?
  • an authenticated user who sends Web Socket messages using a message type to which their profile wouldn’t normally allow access?
  • a malicious user bypassing EWD.js’s Web Socket messaging APIs and sending an otherwise correctly-structured EWD.js Web Socket message using the raw Web Socket APIs?

One way in which all three of these possible attack vectors are counteracted is by wrapping  inside a JavaScript closure the actual mechanism by which EWD.js packages up and transmits its Web Socket Messages: its actions and the variables and functions it uses are private to that closure and therefore not accessible from the JavaScript Console.

Having created that closure, EWD.js then destroys the publicly accessible instance of Socket.io, the Web Socket library used by EWD.js.  This prevents Web Socket messages from being sent over the registered connection via a JavaScript console, except via the built-in EWD.js API that is protected within the closure.

Otherwise, damage is prevented by defensive coding at the back-end within the handler functions for each message type.  When a user successfully logs in, the back-end handler function should always invoke a special function:

ewd.session.setAuthenticated();

This sets a flag in the back-end User Session that indicates that this user is, indeed, properly authenticated.

The handler functions for all other message types should only be capable of being invoked if this flag is set.  This is done by wrapping the handler’s logic inside the following conditional clause:

if (ewd.session.isAuthenticated) {...}

For example:

getVitals: function(params, ewd) {
  if (ewd.session.isAuthenticated) {
    // processing takes place here for authenticated users only
  }
}

This simple step renders futile any attempt by a malicious user to access back-end message handlers without first logging in as a bona fide user.

It is also the responsibility of the developer to ensure that back-end message handler functions check the profile of the user to ensure that they have the authority to perform that function: a bona fide user who has successfully logged in could, in theory, use the JavaScript console to invoke the official EWD.js messaging API and construct their own unauthorised message to see what happens.

These, then, are the mechanisms at work within EWD.js to protect browser-based applications from the malicious intent of the Wild West.  I’ll be watching for new potential attack vectors and potential vulnerabilities coming to light, and plugging any gaps as required.  Please let me know if you become aware of, or can envisage any potential security holes in the mechanisms it currently employs.  Hopefully it makes clear just how many opportunities there are potentially for attacks, and the extent to which a framework such as EWD.js has to provide built-in, automated solutions.

How EWD.js Secures its Web Service Interface

In broad terms there are three ways in which Web Services are implemented within the industry:

  • as simple HTTP/HTTPS services, usually using GET and/or POST requests, with the actions of the services determined by name/value pairs within the URL’s query string or HTTP request payload.  A good example is Amazon Web Services who use such a technique for many, if not all, of their Web Services.
  • as Simple Object Access Protocol (SOAP) services.  SOAP is an XML-based standard for defining Remote Procedure Calls (RPC)  which is often augmented by the Web Services Description Language (WSDL) which is designed to allow automatic discovery and invocation of SOAP services.  SOAP/WSDL is thankfully going distinctly out of fashion, largely because it is exceptionally verbose, overly complex for what it aims to achieve, and inefficient to parse and process.
  • using the principles of Representational State Transfer (REST): a set of architectural style principles for using HTTP syntax in an efficient, intuitive and lightweight way, to represent the actions you want to represent within your Web Services.  REST underpins many new and emerging Web Service-based standards, the most notable within the Healthcare IT domain being HL7 FHIR.

All three approaches share a common underpinning technology: they all make use of the HTTP/HTTPS protocol (in theory SOAP isn’t limited to HTTP, but its overwhelming use in practice is HTTP/HTTPS-based).

As such, when you expose an application and its associated database as a set of web services, you’re making it available over a connectionless protocol, and therefore you need to be sure you figure out a sound and viable way of preventing unauthorised access by clients that are attempting to pretend to be valid ones.

For a variety of reasons, the built-in Web Service interface that is provided by EWD.js uses the first option: simple HTTP-based services, accessed using GET or POST requests.  In order to make it secure, I implemented the exact same technique used by Amazon Web Services, eg to provide secure access over HTTPS for a number of their services including their original cloud database, SimpleDB.  This security works as follows:

Every person or client that wants to access a set of web services must be registered on the EWD.js system.  When registered, the person or client is issued with two text strings: an Access Id and a Secret Key.  EWD.js provides an application that can be used by the system administrator to register Web Service users.  Both EWD.js and the registered person or client know both credentials.  The Secret Key is, as its name implies, something that must be kept secret from everyone else.

When a registered user sends a Web Service HTTP(S) request to  EWD.js, not only must it be recognisable to EWD.js as a valid request for an existing, recognised service, but it must also contain three extra name/value pairs:

  • a time-stamp, denoting the date and time the request was sent;
  • the user’s or client’s Access Id
  • a digital signature, actually an HMAC-SHA256 digest, created from a normalised version of the HTTP request, encrypted using the Secret Key

The process is identical to that used for SimpleDB.

Whenever EWD.js receives what purports to be an incoming Web Service request, it goes through the following steps:

it rejects and returns a 40x error response for any requests that:

  • are not correctly structured or meaningful
  • do not include an Access Id
  • include an invalid Access Id
  • do not include a digital signature

EWD.js then removes the signature name/value pair from the request, normalises it in the same way as the client would have done,  looks up the Secret Key that is registered against the Access Id and creates an HMAC-SHA256 digest from the request by using that Secret Key.  If the signature it creates is the same as the one that was sent with the incoming request, it can be certain that, unless the Access Id and Secret Key have been stolen:

  • the request is genuinely from the registered user and;
  • the request cannot have been tampered with en route.

Note that by ensuring that the user or client includes a time-stamp name/value pair, no two incoming HTTP requests can ever have the same signature, even if the request is otherwise identical to ones previously received from the same user.

This is a very secure mechanism – basically as secure as that used by Amazon Web Services, since it is identical!  By using this mechanism, EWD.js web services are only available for use by registered users or clients.

Furthermore, during the registration process on an EWD.js Server, the user or client is granted rights to only those applications/services for which they are allowed access.  Even if their requests are correctly signed, they can only access those EWD.js Web Services that they are entitled to use.

Finally, it is always recommended that EWD.js is configured to use SSL/HTTPS.  By doing so, both the Web Socket messages used for interactive applications and the HTTP requests used for Web Services are encrypted before transmission.  EWD.js supports SSL/HTTPS “out of the box”.

How the EWD REST Server Applies Security

Whilst the highly-secure but otherwise simple HTTP-based web services provide the sole means of accessing Web Services on an EWD.js server, it became clear that a growing number of services, in particular HL7 FHIR, were requiring the use of REST-based web services and that a means had to be found for EWD.js to not only support REST, but also do so in a way that did not compromise its existing security.

Rather than implement support for REST within EWD.js, I decided to make use of an off-the-shelf Node.js module named Restify: this is a mature, tried and tested module that has pretty much become the de facto REST server implementation for Node.js.  It is a fully-fledged REST server module, implementing all the capabilities and nuances of REST, but, by being a module, allows for the way in which incoming REST requests are processed to be customised in any way that is required.

The design for the EWD REST server was decided upon at a very early stage.  It would perform three roles:

  • it would handle the basic validation of all incoming REST requests to ensure that they were correctly-formed REST requests, recognisable as ones that should be processed by an EWD.js server;
  • it would be able to route incoming REST requests to one or more of a potential pool of EWD.js servers.  The routing would be defined by the first of the elements within the REST request’s URL path;
  • it would rewrite the incoming REST request as a digitally signed EWD.js HTTP request prior to it being re-routed to the EWD.js server.

The second of these roles is implemented via a simple JSON-based lookup table that is defined in the EWD REST Server’s configuration: the table maps the first URL path element string to the hostname/port of an EWD.js server.  Incoming EWD REST requests are of the following format:

  http://my.ewdrest.com:8081/somewhere/myService/further/path/elements....etc

So in the example above, the request will be routed to the EWD.js server that is denoted by the pseudonym somewhere.

In order to perform the last of its roles, ie rewriting the REST request as a digitally-signed EWD.js-formatted HTTP request, the EWD REST Server must be registered on the EWD.js server to which the request is being re-routed, and must therefore have a valid Access Id and Secret Key.  These credentials are included in the routing lookup table.  For the example REST Request above, this lookup table might look like this:

  
     server: {
       somewhere: {
         host: 'www.somewhere.com',
         port: 8080,
         ssl: true,
         secretKey: 'TakeARest!',
         accessId: 'RESTServer'
       }
     }

This provides the EWD REST server with all the information it needs to digitally sign and route an incoming REST request for the somewhere server to the correct endpoint EWD.js server.

As many EWD.js servers as you like can be defined in an EWD REST Server’s lookup table.  The REST Server must be registered on each one, usually with a different and unique Access Id and Secret Key.

So, security between the EWD REST Server and the EWD.js Servers that actually handle the remapped REST requests is tightly-controlled using the mechanisms that are built-in to EWD.js.  What about the security applied to REST requests?

The standard approach in REST is to make use of the Authorization HTTP Header.  Typically the scenario is as follows:

  • an initial REST request, typically a GET, is used to login or authenticate the user.  This request does not include any Authorization header
  • if valid credentials (eg username and password) were used in the login/authenticate REST request, the back-end (in our case the EWD.js) server returns a security token of some sort to the REST Client as part of the REST Response.  In the case of EWD.js, it returns a Session Token – ie exactly the same token that would otherwise be used for inclusion with Web Socket messages.
  • subsequent REST requests, asking for methods/services that are only accessible by authenticated users, must include the token as the Authorization HTTP Header value.  This token is added to the rewritten EWD.js HTTP request that is re-routed to the EWD.js server, and allows EWD.js to authenticate the request as having come from a bona fide authenticated user and also, optionally, associate the incoming request with an EWD.js User Session.
  • In doing so, it is possible for EWD.js-based REST Services to make use of information that is stored in a temporary Session rather than expose any risks that might be potentially associated with sending that information back and forwards between the REST Client and back-end EWD.js server.  The performance overhead of using an EWD.js session in conjunction with REST services is negligible.

As it happens,  the initial login request can be made even more secure, as demonstrated in the example applications that are included with the VistA Installer.

Conclusions

As I hope is now clear, EWD.js, together with its associated EWD REST Server provides a very secure environment for interactive applications, HTTP-based Web Services and REST services.  The mechanisms are based on tried and tested techniques, including those that have been successfully used by the predecessor to EWD.js (known simply as EWD), techniques used by Amazon Web Services and those that are standard REST practices.  In the case of the token-based security techniques that have been borrowed from “classic” EWD, these have always passed repeated, detailed scrutiny by major security auditors, contracted by the largest users of EWD.

The security mechanisms I’ve described are applied identically to EWD.js systems regardless of the back-end database they use: ie either  GT.M or Caché (and even MongoDB).

EWD.js is, today, capable of addressing many of the security issues that surround the use of browser-based applications and Web Services for which projects within the VA are still struggling to find workable solutions.  Perhaps it’s time they took a more detailed look at EWD.js?

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: