.. _rfc18:

==============================================
MS RFC 18: Encryption of passwords in mapfiles
==============================================

:Date:  2006/05/26
:Author: Daniel Morissette
:Contact: dmorissette at mapgears.com
:Last Edited: 2006/08/11
:Status: Completed (2006/08/11)
:Version: MapServer 4.10

Overview
--------

This proposal provides a mechanism to protect database connection passwords 
used inside :ref:`mapfiles <mapfile>` by encrypting them instead of including 
them in plain text.

Technical Solution
------------------

MapServer will be extended to allow the use of encrypted passwords as part 
of the CONNECTION string for the following layer types:

* :ref:`Oracle Spatial <oci>`
* :ref:`PostGIS <input_postgis>`
* :ref:`ESRI SDE <arcsde>`
* :ref:`OGR <ogr>`

The Tiny Encryption Algorithm (TEA) at 
http://www.simonshepherd.supanet.com/tea.htm will be used for the 
encryption/decryption functions.

The implementation details follow...


Encryption key
--------------

In order to safely protect the encrypted information, an encryption key will 
be required by this mechanism. The key will NOT be stored in the mapfile: it 
will be stored in a separate file on the server and should be kept in a 
safe area by the server administrator (especially outside of the web 
server's document directories). 

The location of the encryption key can be specified by two mechanisms, 
either by setting the environment variable MS_ENCRYPTION_KEY or using a 
CONFIG directive:

::

 CONFIG MS_ENCRYPTION_KEY "/path/to/mykey.txt"

New "msencrypt" command-line utility
------------------------------------

A "msencrypt" command-line utility will be provided to create an encryption 
key and to encrypt passwords (or any string) for use in a mapfile. 

To create an encryption key:

::

  msencrypt -keygen /path/to/mykey.txt

To encrypt a password or any string:

::

  msencrypt -key /path/to/mykey.txt <string_to_encrypt>

If the MS_ENCRYPTION_KEY environment variable is set then the -key 
argument does not need to be specified.


Encoding of encrypted strings
-----------------------------

Since the result of encryption is binary data that is not suitable for 
inclusion directly in a MapServer mapfile, hex encoding will be used for the 
encrypted strings in the mapfile as well as for storing the encryption 
key to disk.

The { and } characters will be used as delimiters for encrypted strings 
inside database CONNECTIONs. This will allow the use of either plain text or 
encrypted passwords in mapfiles without any backwards compatibility issues.

e.g. 

::

   CONNECTIONTYPE ORACLESPATIAL
   CONNECTION "user/{MIIBugIBAAKBgQCP0Yj+Seh8==}@service"

Any part of a CONNECTION string can be encrypted and not just the password. 
This will allow protecting other information such as login name, hostname 
or port numbers if necessary. 

For reference, here are examples of typical connection strings for the 
layer types that will be affected:

::

   CONNECTIONTYPE POSTGIS
   CONNECTION "host=yourhostname dbname=yourdatabasename user=yourdbusername password=yourdbpassword port=yourpgport"

   CONNECTIONTYPE SDE
   CONNECTION "sdemachine.iastate.edu,port:5151,sde,username,password"

   CONNECTIONTYPE ORACLESPATIAL
   CONNECTION "user/pwd@service"

   CONNECTIONTYPE OGR
   CONNECTION "OCI:user/pwd@service"


Modifications to the source code
--------------------------------

A msDecryptString() function will be created, it will take a CONNECTION 
string as input and decrypt any encrypted component that it may find in it. 
This function will be called by the various msXXXLayerOpen() methods before 
opening the connection to the database. 

::

 char *msDecryptString(mapObj *map, const char *string)

The first time that msDecryptString() is called for a given mapfile, it will 
load the encryption key from the file and store the key in a new private 
member of the mapObj (char * encryption_key).

To reduce the chances of false matches in long CONNECTION strings such as 
OGR VRT data sources, msDecryptString() function will look for a pair of 
{ + }, and then verify that all chars in the block are valid hex encoding 
chars (0-9,A-F) before proceeding with decryption.

Note that the decrypted string will never be stored in the layerObj, it will 
be kept local to the function that opens the connection and destroyed as 
soon as the function is done with it. This is to prevent exposing the 
decrypted information in error messages or in calls to msSaveMap().

Files affected
--------------

::

 map.h
 mapfile.c
 maporaclespatial.c
 mappostgis.c
 mappostgresql.c
 mapsde.c
 mapogr.cpp


Backwards compatibility issues
------------------------------

None.


Bug ID
------

1792: https://github.com/mapserver/mapserver/issues/1792

Voting history
--------------

Adopted on 2006/06/01.
+1: FrankW, DanielM, HowardB, YewondwossenA, SteveW


Comments from the review period
-------------------------------

* There were concerns about the use of the {...} delimiter to indicate 
  encrypted strings inside CONNECTIONs. Since there was not a better 
  alternative we will stick to that.

* There was a suggestion to use an ENCRYPTION_KEY mapfile keyword 
  instead of CONFIG MS_ENCRYPTION_KEY. Since there was no strong argument 
  either way we decided to stick to CONFIG MS_ENCRYPTION_KEY.

* There was a suggestion to consider the Blowfish algorithm 
  (http://www.schneier.com/blowfish.html) instead of TEA. The sample 
  implementations of Blowfish would require much more work to integrate than 
  TEA, and since TEA is public domain and so much simpler (simpler is 
  better!), we'll stick to TEA for now and can always change the underlying 
  algorithm at a later time if we find that TEA is too weak (which doesn't 
  appear to be an issue).

* Will the encryption methods be made available to MapScript? No plan to do 
  so at this time, but this could easily be added later on.

* Since the user running the web server (and MapServer) needs to have 
  permissions to read the key, any web server process or user with permissions 
  to read the key can decrypt the passwords using a trivial program. It 
  should be made very clear in the documentation that this is just simple 
  obfuscation and is by no means secure and that users should not place 
  valuable passwords in mapfiles encrypted or not. 
