7 Example code
Examples of a simple server and client (server.pl
and
client.pl
as well as a simple HTTPS server (https.pl
)
can be found in the example directory which is located in
doc/packages/examples/ssl
relative to the SWI-Prolog
installation directory. The etc
directory contains example
certificate files as well as a README
on the creation of
certificates using OpenSSL tools.
7.1 Accessing an HTTPS server
Accessing an https://
server can be achieved using the
code skeleton below. The line :- use_module(library(http/http_ssl_plugin)).
can actually be omitted because the plugin is dynamically loaded by
http_open/3
if the https
scheme is detected. See section
5 for more information about security aspects.
:- use_module(library(http/http_open)). :- use_module(library(http/http_ssl_plugin)). ..., http_open(HTTPS_url, In, []), ...
7.2 Creating an HTTPS server
The SWI-Prolog infrastructure provides two main ways to launch an HTTPS server:
- Using
library(http/thread_httpd)
, the server is started in HTTPS mode by adding an optionssl/1
to http_server/2. The argument ofssl/1
is an option list that is passed as the third argument to ssl_context/3. - Using
library(http/http_unix_daemon)
, an HTTPS server is started by using the command line argument--https
.
Two items are typically specified as, respectively, options or additional command line arguments:
- server certificate. This identifies the server and acts as a public key for the encryption.
- private key of the server, which must be kept secret. The key may
be protected by a password. If this is the case, the server must provide
the password by means of the
password
option, thepem_password_hook
callback or, in case of the Unix daemon, via the--pwfile
or--password
command line options.
Here is an example that uses the self-signed demo certificates distributed with the SSL package. As is typical for publicly accessible HTTPS servers, this version does not require a certificate from the client:
:- use_module(library(http/thread_httpd)). :- use_module(library(http/http_ssl_plugin)). https_server(Port, Options) :- http_server(reply, [ port(Port), ssl([ certificate_file('etc/server/server-cert.pem'), key_file('etc/server/server-key.pem'), password("apenoot1") ]) | Options ]).
There are two hooks that let you extend HTTPS servers with custom definitions:
http:ssl_server_create_hook(+SSL0, -SSL, +Options)
: This extensible predicate is called exactly once, after creating an HTTPS server with Options. If this predicate succeeds,SSL
is the context that is used for negotiating all new connections. Otherwise,SSL0
is used, which is the context that was created with the given options.http:ssl_server_open_client_hook(+SSL0, -SSL, +Options)
: This predicate is called before each connection that the server negotiates with a client. If this predicate succeeds,SSL
is the context that is used for the new connection. Otherwise,SSL0
is used, which is the context that was created when launching the server.
Important use cases of these hooks are running dual-stack RSA/ECDSA servers, updating certificates while the server keeps running, and tweaking SSL parameters for connections. Use ssl_set_options/3 to create and configure copies of existing contexts in these hooks.
The example file https.pl
also provides a server that
does require the client to show its certificate. This provides an
additional level of security, often used to allow a selected set of
clients to perform sensitive tasks.
Note that a single Prolog program can call http_server/2
with different parameters to provide services at several security levels
as described below. These servers can either use their own dispatching
or commonly use http_dispatch/1
and check the port
property of the request to verify they
are called with the desired security level. If a service is approached
at a too low level of security, the handler can deny access or use HTTP
redirect to send the client to to appropriate interface.
- A plain HTTP server at port 80. This can either be used for non-sensitive information or for redirecting to a more secure service.
- An HTTPS server at port 443 for sensitive services to the general public.
- An HTTPS server that demands for a client key on a selected port for administrative tasks or sensitive machine-to-machine communication.
7.3 HTTPS behind a proxy
The above expects Prolog to be accessible directly from the internet. This is becoming more popular now that services are often deployed using virtualization. If the Prolog services are placed behind a reverse proxy, HTTPS implementation is the task of the proxy server (e.g., Apache or Nginx). The communication from the proxy server to the Prolog server can use either plain HTTP or HTTPS. As plain HTTP is easier to setup and faster, this is typically preferred if the network between the proxy server and Prolog server can be trusted.
Note that the proxy server must decrypt the HTTPS traffic because it must decide on the destination based on the encrypted HTTP header. Port forwarding provides another option to make a server running on a machine that is not directly connected to the internet visible. It is not needed to decrypt the traffic using port forwarding, but it is also not possible to realise virtual hosts or path-based proxy rules.
Virtual hosts for HTTPS are available via Server Name Indication (SNI). This is a TLS extension that allows servers to host different domains from the same IP address. See the sni_hook/1 option of ssl_context/3 for more information.