Getting started with CouchDB and MongoDB, Part II: Beginning with Security

In the first part of this series I discussed how can we perform CRUD operation in MongoDB and CouchDB. In this part we will look into security features of MongoDB and CouchDB. In the next two installments of this series I will go into how to apply the configuration that are described here and how to write codes that work with them.

Basic security requirements

There are some basic features and functionalities which are required by different applications, in addition to tons of other more advanced fine grained features, which one can expect a semi-structured data storage server to provide. If the not provided, other measures should be applied to limit the effect of missing features risks. The basic features are as listed below:

  • Authentication: Authentication refers to ensuring that if a token is presented to our system the system can verify that the token is valid, for example a username can be verified using the password that accompany it.
  • Access control: To limit the access to specific resources/ set of resources to an authenticated client or a group of authenticated clients sharing common characteristics like a assigned role_name.
  • Transport safety: To ensure that the data is being transferred over the network safely without possibility of tampering or reading depending on the required level of confidentiality.
  • On-Disk/In-memory Data Encryption: To keep the data encrypted on disk to prevent RAW access to the data without presence of the decryption key/token. Same applies to the systems that are data memory intensive, the memory data in memory should be protected from memory dump/views.

General Security precautions

  • Do not run the server on default network interface which it is configured, usually 0.0.0.0 which means all available interfaces. Imagine you having a LAN and WAN interface and you want your NoSQL storage to only listen on the LAN interface while by default it listens on all interfaces (including your outbound WAN).
  • Do not use the default port numbers, change the port numbers that your backend application server, database, NoSQL storage, ABCD network server listen on. No need to wait for intrusion on the default port number.
  • Do not run your network server, e.g NoSQL server on root or any other privileged user.  Create a user which is relaxed enough in disk/network access to let the network server perform its task and not relaxer!
  • Do not let the above user to have access to any portion of file server other than the one that it requires.
  • Enable disk quota!
  • If on-disk/in-memory encryption is supported depending on sensitivity of the data, enable it.
  • Enable transport security. One way or another transport security is required to prevent others peeping, tampering the data or request responses!
  • Make sure you enable your iptable and limit the above user to only have access to port/interfaces that it meant to have access nothing more.
  • Disable any sample welcome page, any default “I am UP” message, any default “Welcome page” or anything else that your network server may have out of the box. This will prevent people from peeping into seeing what version of what network server you are running.
  • Disable any extra interface/communication channel that your network server has and you are not using it. E.g In an application server we just don’t need the JMX interface and thus we disable it rather than having a door into the application server, although the door is locked but…
  • Do not use anything default, no port, no default username, no default password, no default welcome message, no default… Nothing default!

MongoDB and Security

Below is some description on how MongoDB cover the basic security requirements.

  • Authentication: Supports two types of access. Either no authentication is enabled and anonymous users can do read/write or authentication is enabled (per database) and users are authenticated and then checked for their authorization before accessing the database. At the token level, CouchDB supports OAuth, cookie based authentication and http basic authentication. We will go into details of these in the next installments of this blog series.
  • Authorization: Supports role based access control. There are several roles which can be assigned to users. each role add some more privilege to the user(remember unauthenticated users cannot interact with the database when authentication is enabled). Details of the roles MongoDB access control documentation.
  • Transport Security: In the community edition there is no build-in transport security out of the box, you can use the MongoDB enterprise or you need to build it from the source to get SSL included in your non-enterprise copy. Procedure described at Configure SSL.
  • On-disk/In-memory encryption: I am not aware of any built-in support for any of these. One possibility is to use OS level disk encryption and/or use application level encryption for the sensitive fields, which imposes limitation on indexing and similarity searches, in the document.

CouchDB and Security

Below is some description on how Apache CouchDB cover the basic security requirements.

  • Authentication: By default any connection to CouchDB has access to perform CRUD on the server (creating/reading/deleting databases) and also CRUD operations on documents stored in the databases. When authentication is enabled, we go into how each one of these tasks can be performed in next blog entry, the user’s credentials is checked to let it perform CRUD on server or on databases or to perform read action on the database.
  • Authorization: There are 3 roles in CouchDB, the server admin role which can do anything and everything possible in the server, the database admin role on a database and the read-only role on a database.
  • Transport: Apache CouchDB has built-in supports for transport security using SSL and thus all communication that requires transport security (encryption, integrity) can be made over HTTPS.
  • On-Disk/In-memory encryption: I am not aware of any built-in support for any of these. One possibility is to use OS level disk encryption and/or use application level encryption for the sensitive fields in the document. Application level encryption will imposes limitation on indexing and similarity searches.
This blog entry is wrote based on CouchDB 1.3.1 and MongoDB 2.4.5 and thus the descriptions are valid for these versions and they may differ in other versions. The sample codes should work with the mentioned versions and any newer release.

How REST interface covers for the absence of JMX/AMX administration and management interface in GlassFish 3.1

For sometime I wanted to write this entry and explain what happened to GlassFish JMX/AMX management and administration interface but being busy with other stuff prevented me from doing so. This article here can be an upgrade to my other article about GlassFish 3.0 JMX administration interface which I wrote while ago. Long story short, in GlassFish 3.1 the AMX/JMX is no longer available and instead we can use the REST interface to change the server settings and perform all administration/management and monitoring activities we need. There are fair number of articles and blog entries all over the web about the RESTful interface which I included them at the end of this blog. Firs of all the rest interface is available trough the administration console application meaning that we can access the interface using a URL similar to: http://localhost:4848/management/domain/ The administration console and the rest interface  are running on a separate virtual server and therefore a separate HTTP Listener and if required transport configuration. What I will explain here will be the following items:

  • How to use Apache HttpClient to perform administration tasks using GlassFish REST interface
  • How to find the request parameters for different commands.
  • GlassFish administration, authentication and transport security

How to use Apache HttpClient to interact with GlassFish administration and management application

Now back to the RESTful interface, this is a HTTP based interaction channel with the GlassFish administration infrastructure which basically allows us to do almost anything possible to do using asadmin trhough HTTP in a RESTful manner. We can use basically any programming language capable to writing on a socket to interact with the RESTFul interface. Here we will use Apache HTTPClient to take care of sending the commands to GlassFish RESTFul console. When using GlassFish REST management we can use any of the POST/GET and DELETE methods to perform the following tasks:

  • POST: create and partially update a resource
  • GET: get information like details of a connection pool
  • DELETE: to delete a resource

Following sample code shows how to use the  to perform some basic operations including updating a resource, getting some resources list, creating a resource and finally deleting it.

[java]
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.util.logging.Logger;

import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;

/**
*
* @author Masoud Kalali
*/
public class AdminGlassFish {

//change the ports to your own settng
private static final String ADMINISTRATION_URL = "http://localhost:4848/management";
private static final String MONITORING_URL = "http://localhost:4848/monitoring";
private static final String CONTENT_TYPE_JSON = "application/json";
private static final String CONTENT_TYPE_XML = "application/xml";
private static final String ACCEPT_ALL = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
private static final Logger LOG = Logger.getLogger(AdminGlassFish.class.getName());

public static void main(String args[]) throws IOException, HttpException, URISyntaxException {

//just chaning the indent level for the JSON and XML output to make them readable, for humans…
String prettyFormatRestInterfaceOutput = "{"indentLevel":2}";
String response = postInformation("/domain/configs/config/server-config/_set-rest-admin-config", prettyFormatRestInterfaceOutput);
LOG.info(response);
//getting list of all JDBC resources
String jdbcResources = getInformation("/domain/resources/list-jdbc-resources");
LOG.info(jdbcResources);

// creating a JDBC resource on top of the default pool
String createJDBCResource = "{"id":"jdbc/Made-By-Rest","poolName":"DerbyPool"}";
String resourceCreationResponse = postInformation("/domain/resources/jdbc-resource", createJDBCResource);
LOG.info(resourceCreationResponse);

// deleting a JDBC resource
String deletionReponse = deleteResource("/domain/resources/jdbc-resource/jdbc%2FMade-By-Rest");
LOG.info(deletionReponse);

}

//using HTTP get
public static String getInformation(String resourcePath) throws IOException, AuthenticationException {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpG = new HttpGet(ADMINISTRATION_URL + resourcePath);
httpG.setHeader("Accept", CONTENT_TYPE_XML);
HttpResponse response = httpClient.execute(httpG);
HttpEntity entity = response.getEntity();
InputStream instream = entity.getContent();
return isToString(instream);
}

//using HTTP post for creating and partially updating resources
public static String postInformation(String resourcePath, String content) throws IOException {
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(ADMINISTRATION_URL + resourcePath);
StringEntity entity = new StringEntity(content);

//setting the content type
entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, CONTENT_TYPE_JSON));
httpPost.addHeader("Accept",ACCEPT_ALL);
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost);

return response.toString();
}

//using HTTP delete to delete a resource
public static String deleteResource(String resourcePath) throws IOException {
HttpClient httpClient = new DefaultHttpClient();
HttpDelete httpDelete = new HttpDelete(ADMINISTRATION_URL + resourcePath);
httpDelete.addHeader("Accept",
ACCEPT_ALL);
HttpResponse response = httpClient.execute(httpDelete);
return response.toString();

}

//converting the get output stream to something printable
private static String isToString(InputStream in) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(in), 1024);
for (String line = br.readLine(); line != null; line = br.readLine()) {
sb.append(line);
}
in.close();
return sb.toString();
}
}
[/java]

You may ask how could one know what are the required attributes names, there are several ways to do it:

  • Look at the reference documents…
  • View the source code of the html page representing that kind of resource, for example for the JDBC resource it is like http://localhost:4848/management/domain/resources/jdbc-resource which if you open it in the browser you will see an html page and viewing its source will give you the names of different attributes. I think the label for the attributes is also the same as the attributes themselves.

  • Submit the above page and monitor the request using your browser plugin, for example in case of chrome and for the JDBC resource it is like the following picture

GlassFish administration, authentication and transport security

By default when we install GlassFish or we create a domain the domain administration console is not protected by authentication nor it is protected by HTTPS so whatever we send to the application server from through this channel will be readable by someone sniffing around. Therefore you may need to enable authentication using the following command:

./asadmin change-admin-password

You may ask now that we enabled the authenticaiton for the admin console, how we can use it by our sample code, the answer is quite simple,  Just set the credentials for the request object and you are done. Something like:

[java]
UsernamePasswordCredentials cred = new UsernamePasswordCredentials("admin", "admin");
httpget.addHeader(new BasicScheme().authenticate(cred, httpget));
[/java]

Make sure that you are using correct username and passwords as well as correct request object. In this case the request object is httpGet

Now about the HTTPs to have have encryption during the transport we need to enable the SSL for the admin HTTP listener. following steps show how to use the RESTFul interface through a browser to enable HTTPS for the admin console. When using the browser, GlassFish admin console shows basic HML forms for different resources.

  1. Open the http://localhost:4848/management/domain/configs/config/server-config/network-config/protocols/protocol/admin-listener in the browser
  2. Select true for security-enabled option element
  3. Click Update to save the settings.
  4. Restart server using http://localhost:4848/management/domain/restart

The above steps have the same effect as

./asadmin enable-secure-admin

This will enable the SSL layer for the admin-listener but it will use the default, self singed certificate. Here I explained how to install a GoDaddy digital certificate into GlassFish application server to be sure that none can listen during the transport of command parameters and on the other hand the certificate is valid instead of being self signed. And here I explained how one can use the EJBCA to setup and use an small inter-corporate certificate authority with GlassFish, though the manual is a little old but it will give you enough understanding to use the newer version of EJBCA.

If you are asking about how our small sample application can work with this dummy self signed certificate of GlassFish you need to wait till next time that I will explain how to bypass the invalid certificate installed on our test server.

In the next part of this series I will cover more details on the monitoring part as well as discussing  how to bypass the self signed Digital certificate during the development…

My slides for Java EE Security session at JavaForum meeting 69

On the 7th of december I presented the “Security in Java EE platform: what is included, what is missing” session in the JavaForum meeting.

Although I arrived somehow late and left  right after the last presentation which was done by Chet Hendrickson but I can say that the athmospher was really friendly and enjoyable. I enjoyed the HTML 5 session and more than that I enjoyed the session presented by Chet, his way of presenting the session was different and pretty fun.

Following album contains some photos from the session.