Securing Kitura

We, at IBM, are always looking for ways to improve security of our server applications and that’s why our team is so excited about our new release of the Kitura framework. In this release, we have not only made it simple to get your server up and running (takes only 5 lines of code!!) but today we are officially releasing Kitura middleware that additionally protects and secures your application server.

Using Swift as the starting point for Kitura allow us to create an application with multi-stack security: Swift has been designed as a type-safe language. It includes code access control and (for swift-only programs,) protection against null pointers via optionals and explicit types, which reduce unpredictable behavior and thus potential for exploit. Kitura is built on top of this language and thus inherits its strong security features.

In this post series, we will show how easy it is to create a secure application server with Kitura. In this first part of the series, we will build a simple Kitura API that is served on top of SSL/TLS. This means that our application server will support private and authenticated communication. In our next post, we will add a protected API and show how an API can be locked down with user authentication via HTTPS Basic and OAuth2 authentication.

Background: SSL/TLS

Transport Layer Security (TLS) is a protocol for encrypting data that is sent over the Internet and it can provide three important features:

  • Data Privacy: The data that is exchanged between a server and client is not visible to anyone else;
  • Data Integrity: The data that is exchanged between a server and client cannot be modified by anyone else;
  • Server Authenticity: The server can prove its identity to the client, thus providing data origin validation.

TLS evolved out of Netscape’s Secure Sockets Layer (SSL) protocol in order to fix many of its security flaws. The industry still uses the terms somewhat interchangeably for historical reasons. Any web site that you visit starting with https:// rather than http:// is using TLS/SSL for communication between your browser and their server.

To enable TLS, a server needs a certificate and a corresponding secret key. Certificates are files that bind together information about the identity of the owner of a site and the public half of an asymmetric key pair (usually RSA). Certificates are usually digitally signed by a certificate authority (CA) who verifies that the identity information in the certificate is correct. This creates a chain of certificates between the site owner certificate and a CA certificate and transitive trust. Assuming that we trust the CA, we can trust the validity of the server certificate.

BlueSSLService Framework

BlueSSLService is the underlying framework that integrates with Kitura to provide SSL/TLS on macOS and Linux. BlueSSLService is the first Swift-only framework that integrates with the native security libraries on macOS and Linux. Specifically, BlueSSLService integrates with OpenSSL library on Linux and Apple Secure Transport on macOS. This is important, because the developer does not need to install any additional packages on their platform of choice. Additionally and more importantly, pre-installed OpenSSL on macOS has been deprecated since OS X v10.7 and later, for binary compatibility reasons. This means you avoid the need to require OpenSSL on macOS, thus avoiding the need to install your own version of this library and statically link it into your program. Finally, since BlueSSLService presents a consistent and unified Swift interface for both macOS and Linux, the developer can simply import BlueSSLService (via Kitura) in their application and know that their application will behave correctly on both macOS and Linux.

Sample Application

Let’s get started. You can follow Kitura wiki to create the following sample Kitura app with a GET API that outputs Hello World:

import Kitura
let router = Router()

router.get("/") {
    request, response, next in
    response.send("Hello, World!")
    next()
}

Kitura.addHTTPServer(onPort: 8090, with: router)
Kitura.run()

You should be using at minimum Kitura 1.0 which uses Swift 3.0. We want to serve our data over https on both macOS and Linux using a self-signed certificate. You can download an extended version of this sample app which uses both self-signed and chained certificates from here which includes sample certificates for your own testing.

To enable TLS in Kitura, we must first setup our server’s certificate and key pair. The certificate can be either a self-signed certificate or a certificate chain whereby the server certificate is signed by a CA. Because of the limitations of the native frameworks on each platform, Kitura currently supports PEM certificate format on Linux, and PKCS#12 on macOS. This means that if you want to develop an application on macOS before transitioning to Linux, you need to use the appropriate certificate format and the appropriate config prototype for each platform.

In this example, we have created a self-signed PEM certificate using the following OpenSSL commands:

// generate a 2048bit RSA key
openssl genrsa -out key.pem 2048

// create a certificate signing request used to generate the cert
openssl req -new -sha256 -key key.pem -out csr.csr

// create the certificate
openssl req -x509 -sha256 -days 365 -key key.pem -in csr.csr -out cert.pem

// convert cert into PKCS#12 format:
openssl pkcs12 -export -out cert.pfx -inkey key.pem -in cert.pem

It should be noted that PKCS#12 format and PEM are different in their encoding as well as data aggregation. PEM is a Base64-encoded ASCII format of public and private data. In contrast, PKCS#12 is a binary blob of both public and private data that can be password encrypted. This is why the SSL config init takes in the cert and the key files separately, where as for PKCS#12, it takes in one blob that contains both the certificate and the key, and optionally a password.

Place your certificate and key in /tmp/Creds folder.

It should be noted that an alternative means of converting PEM certificates to PKCS#12 is using this tool. This tool is particularly handy when converting certificate chains between formats.

If you want to create a CA-signed certificate chain, an additional handy tool to use is Let’s Encrypt, a free, automated and open CA, provided by the Internet Security Research Group (ISRG).

We are now ready to configure Kitura with our certificate and key and enable TLS on our server. Since this is a self-signed certificate, we must set the parameter usingSelfSignedCerts to true in the SSLConfig below.

#if os(Linux)

let myCertFile = "/tmp/Creds/cert.pem"
let myKeyFile = "/tmp/Creds/key.pem"
        
let mySSLConfig =  SSLConfig(withCACertificateDirectory: nil, 
                             usingCertificateFile: myCertFile, 
                             withKeyFile: myKeyFile, 
                             usingSelfSignedCerts: true)
#else // on macOS

let myCertKeyFile = "/tmp/Creds/cert.pfx"
        
let mySSLConfig =  SSLConfig(withChainFilePath: myCertKeyFile,
                             withPassword: "password",
                             usingSelfSignedCerts: true)

#endif

router.get("/") {
    request, response, next in
    response.send("Hello, World!")
    next()
}

Kitura.addHTTPServer(onPort: 8090, with: router, withSSL: mySSLConfig)
Next we compile our application using the Swift Package Manager (SwiftPM), which first resolves and fetches the dependencies and then builds our project. We do this by running swift build in our project directory. Once the project is built, we run the executable which was placed in the .build/debug directory. After the executable is running and listening for connections on localhost:8090, you can test out the application by opening a browser on:
https://localhost:8090

At this point your browser might give you a warning that the SSL certificate it is validating is self-signed. Since you are accessing your own server this isn’t a problem at all, and you can simply tell your web-browser to accept the self-signed SSL certificate and continue. In general though, your browser should only trust server certificates which are issued by a valid CA.

Notice the https in your URL! You are running Kitura with TLS! This means that the data your application transmits is secure and the server your users are connecting to is authenticated.

But wait! There’s more!

This is just the beginning of a long journey to securing your application! In future posts, we will go through:
  • Kitura-Credentials: Protect endpoints with user authentication using a variety of diverse authentication mechanism plugins.
  • Kitura-Session: Create secure sessions with private and authenticated cookies
  • Kitura-CSRF: Adds protection against Cross-Site Request Forgery (CSRF) attacks where a malicious application causes a user’s web server to perform an unwanted action on behalf of the authenticated user.
  • Kitura-CORS: Cross-Origin Resource Sharing (CORS) allows restricted resources on a web page to be requested from another domain outside the domain from which the resource originated.
In the meantime, learn more about Swift@IBM by visiting our DevCenter.

3 Comments on "Securing Kitura Part 1: Enabling SSL/TLS on your Swift Server"

  1. Is this intended to be a production setup? If i understand correctly, my ssl cert + key must be readable from the user under which my kitura server is runnig. Wouldn’t it be possible in case of an exploit, that the attacker could steel my private key?

    • Hi Christopher, great question!

      The short answer to your question is: No, the above tutorial is for testing and development purposes only. In a production setup, you definitely do not want to use self-signed certificates, rather CA-signed certificate chains. However, if you are using Kitura as your SSL endpoint and you are using proper certificates, then Kitura can definitely be a production-level SSL endpoint server. And to do this, it needs to have access to both your SSL cert and private key. If an attacker compromises your SSL endpoint, then they can compromise your private key. So it is the developer’s responsibility to secure the SSL endpoint.

      This can be done in several ways in a production setting, including:

      • Key protection via encryption: key on disk can be encrypted with a passphrase. This however means that on every server restart, the user needs to enter the passphrase which makes server restart automation difficult (unless passphrase is also kept on disk, which defeats the purpose). Because of this, key encryption is generally not done.
      • Key protection via access control: OS-level access control is adopted to ensure only specific users can access the key.
      • Key isolation: key can be stored off-server, for example in a Hardware Security Module (HSM), but these can be expensive.
      • SSL endpoint isolation: In most production settings, the SSL endpoint is isolated in a DMZ, where the DMZ acts as an interface between the server’s subnet and the external network traffic. DMZs generally consist of a simple reverse proxy (such as haproxy or WebSphere or nginx) or a server that has limited functionality, such as redirecting external traffic to the network resources and decrypting the external traffic. With proper hardening of the DMZ server and additions of gateways/firewalls, the attack surface for compromise of the SSL private key can be reduced substantially.

      The above are just some of the ways the developer can secure their SSL private key storage. It should be noted that there are also many techniques that should be adopted when protecting a production private key, including key rolling, proper revocation handling and forward secrecy.

      Let me know if you have any other questions!

  2. Please note, the version of BlueSSLService described above is located in the master-next branch, not the master. This will be merged shortly.

Join The Discussion

Your email address will not be published. Required fields are marked *