Before implementing encryption on your data at any level (transmission, storage), understand if encrypting the data is necessary. Using SSL will cost hardware resources and will generally slow down your application server.
Always estimate how important is it to encrypt your data and exactly what data you need to encrypt.
Standalone Mode
Remove or Disable Example Content
Although it can be a good idea to keep some example content in a test environment, to check if the server is running correctly, it is not a good practice in production.
Removing the samples will prevent an external client seeing what version of the AS you are running and will also prevent the AS instance being affected by future security bugs on this content.
Delete the example datasource shipped with the default configuration:
<datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
Disable or remove the welcome-content directory by placing "false" as a value on enable-welcome-root
<subsystem xmlns="urn:jboss:domain:web:1.4" default-virtual-server="default-host" native="false">
<connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http"/>
<virtual-server name="default-host" enable-welcome-root="false">
<alias name="localhost"/>
<alias name="example.com"/>
</virtual-server>
</subsystem>
You can also change the alias name according to your needs.
You can remove the directory holding the sample content:
In Linux as the JBoss AS user:
rm -r $JBOSS_HOME/welcome-content
Audit Logging
It is good practice to log the actions on the org.jboss.security class. This category includes all the security related actions on the particular instance of the AS (authentication, failures, administrative changes ..).
It is good to keep these events in a separate file for easy classification and analysis. In this example the file will be called audit.log
Insert a new handler in our logging subsystem
<periodic-rotating-file-handler name="AUDIT" autoflush="true">
<formatter>
<pattern-formatter pattern="%d{HH:mm:ss,SSS}%-5p %c (%t) %s%E%n"/>
</formatter>
<file relative-to="jboss.server.log.dir" path="audit.log"/>
<suffix value=".yyyy-MM-dd"/>
<append value="true"/>
</periodic-rotating-file-handler>
Create a new category and reference the handler created above
<logger category="org.jboss.security">
<level name="TRACE"/>
<handlers>
<handler name="AUDIT"/>
</handlers>
</logger>
Send log to a remote server
Sending logs to a remote location is an excellent way to increase security (preventing log tampering) and improve your application error analysis. Jboss AS7.2 supports a syslog handler designed for this purpose.
Add the syslog handler in your logging subsystem:
In the section:
<subsystem xmlns="urn:jboss:domain:logging:1.1">
...
</subsystem>
Add this handler:
<syslog-handler name="SYSLOG">
<level name="INFO"/>
<hostname value="${jboss.bind.address}"/>
<app-name value="JBossAS7"/>
<server-address value="Your Log Server's IP (ie. 10.1.1.1)"/>
</syslog-handler>
For a more detailed explanation of all the parameters in this handler, please consult the Logging Configuration section of the management guide
Note on Exceptions
Even though JBoss supports a Syslog handler out of the box, some exceptions are often discarded by many syslog compatible servers because the exception message spans in multiple lines.
Please consult the documentation of your log server to understand if multi line logs are supported.
Run your Instance as non privileged user
This is a global requirement for any mission-critical application, your AS 7 instance should never run as root account in a secure environment.
Please refer to your operating system documentation to understand how to run AS7 as non privileged user.
File system permissions of log files
In order to prevent modifications to your log files, you can restrict the OS permissions to only be readable/writable by the JBoss user.
In order to change the location of your log files you can use this Java property at startup jboss.domain.log.dir and set a different log directory (I.E. /var/log/jboss)
-Djboss.domain.log.dir=/var/log/jboss/
Check the documentation of your operating system to understand how to restrict the access to your files.
Datasources
In order to secure your datasources, it is good practice is associate them with a security domain.
This example will implement an Oracle datasource and it will delegate the authentication to a JAAS security domain.
Configure a security domain called "oracle-secure" to use with your datasource:
<security-domains>
<security-domain name="oracle-secure" cache-type="default">
<authentication>
<login-module code="SecureIdentity" flag="required">
<module-option name="username" value="myexpensivedbusername"/>
<module-option name="password" value="myexpensivedbencryptedpassword"/>
<module-option name="managedConnectionFactoryName" value="jboss.jca:service=LocalTxCM,name=MyDS-MyDS"/>
</authentication>
</security-domain>
...
</security-domains>
As you can see, between the <authentication></authentication> tags we have defined a username and a password for our database authentication.
The part:
<login-module code="SecureIdentity" flag="required">
defines which module to use and also to flag it as "required". This means that the client cannot pass the authentication if these credentials are not provided correctly.
The password value can be defined in plain-text or in an encrypted format. If you want to use the encrypted value just use Picketbox and provide the password as input:
java -cp $JBOSS_HOME/modules/org/picketbox/main/picketbox-4.0.6.<beta|final>.jar:$JBOSS_HOME/modules/org/jboss/logging/main/jboss-logging-3.1.0.<some_version>.jar:$CLASSPATH org.picketbox.datasource.security.SecureIdentityLoginModule password
Changing the Key
The result of this operation is an encrypted value, however the key used is hardcoded in the source code, from a security perspective, using a basically public passphrase is exactly the same as non encrypting at all. If you really want to make this secure please change the hardcoded passphrase in Picketbox.
You can possibly change the hardcoded key by modifying the source code of this Class. However, you may need to recompile and test the component yourself.
Using the Vault
Also note this article Securing Passwords on how to use the Vault functionality
Finally you can setup the datasource with your security domain
<datasource jta="true" jndi-name="java:/MyDS" pool-name="MyDS" enabled="true" use-ccm="true">
<connection-url>jdbc:oracle:thin:@myexpensivedatabase:1521:myexpensivedbuser</connection-url>
<driver-class>oracle.jdbc.OracleDriver</driver-class>
<driver>oracle</driver>
<pool>
<min-pool-size>5</min-pool-size>
<max-pool-size>50</max-pool-size>
</pool>
<security>
<security-domain>oracle-secure</security-domain>
</security>
<validation>
<validate-on-match>true</validate-on-match>
<background-validation>false</background-validation>
<check-valid-connection-sql>select 1 from dual</check-valid-connection-sql>
</validation>
<timeout>
<idle-timeout-minutes>1</idle-timeout-minutes>
</timeout>
<statement>
<prepared-statement-cache-size>50</prepared-statement-cache-size>
<share-prepared-statements>true</share-prepared-statements>
</statement>
</datasource>
Your AS is now able to expose a datasource, connect to a database and delegate the authentication part to a security domain with an encrypted password.
Deployment Scanner
The deployment scanner scans the file system where your AS instance is running to automatically deploy any new application copied in your deploy directory. If it is not needed, the deployment scanner must be disabled in order to prevent unauthorized files being deployed.
Just configure the scan-interval parameter as -1 , this will configure the deployment scanner to only allow deployments from console or at instance startup.
<subsystem xmlns="urn:jboss:domain:deployment-scanner:1.1">
<deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="-1"/>
</subsystem>
Web Subsystem
Enable SSL Connector
Enabling the SSL connector for the web subsystem will encrypt everything that is using that particular port
<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="example.com" native="false">
<connector name="https" protocol="HTTP/1.1" scheme="https" socket-binding="https" secure="true" enable-lookups="false">
<ssl name="ssl" password="changeit" certificate-key-file="example.ks" verify-client="true" key-alias="example-alias"/>
</connector>
<virtual-server name="example.com" enable-welcome-root="false">
<alias name="www.example.com"/>
</virtual-server>
...
</subsystem>
For more information on the connector attributes refer to JbossWeb Configuration Reference
Create an entry in the socket binding group for the port of this new connector, if not present
<socket-binding-group name="standard-sockets" default-interface="public"
port-offset="${jboss.socket.binding.port-offset:0}">
...
<socket-binding name="https" port="7443"/>
...
</socket-binding-group>
JSP Regeneration
If you do not need automatic regeneration of JSP pages, set up the Web Subsystem to not regenerate the content automatically. This can prevent someone injecting code in your JSP resources and compiling them without your knowledge.
<connector>
...
</connector>
<virtual-server name="example.com" enable-welcome-root="false">
...
</virtual-server>
<configuration>
<jsp-configuration development="false"/>
</configuration>
The "Development" value set to false will prevent JSP resources being automatically generated and force a restart in order to implement the changes.
Disable stacktrace in response body
Stacktraces in response bodies are useful for quick debugging in development and test environments. However in production, showing stracktraces can leak sensitive information to the client.
To disable this particular functionality, the display-source-fragment directive must be set to false.
<subsystem xmlns="urn:jboss:domain:web:1.1" ... >
....
<configuration>
<jsp-configuration display-source-fragment="false"/>
</configuration>
....
</subsystem>
Webservices Subsystem
SSL Encryption
Define the secure WSDL port leveraging on the Web Subsystem ssl connector.
<subsystem xmlns="urn:jboss:domain:webservices:1.1">
<modify-wsdl-address>true</modify-wsdl-address>
<wsdl-host>10.1.1.1</wsdl-host>
<wsdl-secure-port>7443</wsdl-secure-port> <!-- Must be a secure SSL connector port -->
<endpoint-config name="Standard-Endpoint-Config"/>
<endpoint-config name="Recording-Endpoint-Config">
<pre-handler-chain name="recording-handlers"
protocol-bindings="##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM">
<handler name="RecordingHandler"/>
</pre-handler-chain>
</endpoint-config>
</subsystem>
Please note that <modify-wsdl-address> needs to be set to true in order for the Webservices subsystem to change all the http:// links in your WSDL file to
https://, and instruct the client to go only to the secure version of your resources.
Authentication
To create a security domain for your Webservices endpoints, you can use different login modules. Please consult the Security subsystem configuration for more detailed informations.
In the example a Database module is used.
<security-domains>
<security-domain name="webservices-auth" cache-type="default">
<authentication>
<login-module code="Database" flag="required">
<module-option name="dsJndiName" value="java:/MyDS"/>
<module-option name="principalsQuery"
value="SQL QUERY TO SELECT YOUR USERNAME"/>
<module-option name="rolesQuery"
value="SQL QUERY TO SELECT YOUR ROLE"/>
<module-option name="hashAlgorithm" value="SHA-256"/>
<module-option name="hashEncoding" value="base64"/>
</login-module>
</authentication>
</security-domain>
...
</security-domains>
This security domain will query your database and search if the username/password pair provided to your Webservice by the client are correct.
Reference your new security domain in your code
package my.class.ws;
import org.jboss.ejb3.annotation.SecurityDomain;
import org.jboss.ws.api.annotation.WebContext;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
...
@Stateless
@WebService(name = "Member", targetNamespace = "http://my.ws/example", serviceName = "ExampleWS")
@SOAPBinding(style = SOAPBinding.Style.RPC, parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
@SecurityDomain("webservices-auth")
@RolesAllowed("wsrole")
@WebContext(secureWSDLAccess = true, transportGuarantee = "CONFIDENTIAL", authMethod = "BASIC")
...
The annotation SecurityDomain obviously configure the security domain used for authentication purposes.
The annotation RolesAllowed defines which security roles (from your security domain) are allowed to contact this webservice
The annotation transportGuarantee force the SSL/TLS connection
The annotation authMethod defines which method your webservice will use to authenticate the client.
ORB (JacORB) Subsystem
The AS 7 ORB implementation can be secured by enabling SSL encryption in the JacORB subsystem.
First of all, create a security domain that references your keystore/truststore configuration. We'll call it "ssl-domain"
<security-domains> ....
<security-domain name="ssl-domain">
<jsse keystore-password="changeit" keystore-url="mykeystore.ks" truststore-url="mytruststore.ks" truststore-password="changeit" server-alias="my alias"/>
</security-domain>
....
</security-domains>
To enable this in JacORB setup the tags security-domain and security.
<subsystem xmlns="urn:jboss:domain:jacorb:1.1">
<orb>
<initializers security="on" transactions="spec"/>
</orb>
<security support-ssl="on" security-domain="ssl-domain"/>
</subsystem>
This configuration enables SSL on JacORB. If you want to lock-down this subsystem more, you can find a huge amount of useful informations on the JacORB Official Documentation Page
Messaging subsystem (HornetQ)
Setup a security domain
Like the other subsystems, the messaging subsystem can be linked to a security-domain in order to delegate encryption or authentication settings.
Reference the name of your security domain after the <hornetq-server> element
<subsystem xmlns="urn:jboss:domain:messaging:1.1">
<hornetq-server>
<security-domain>mysecuritydomain</security-domain>
...
</hornetq-server>
</subsystem>
As seen before, the security domain can set up the parameters for encryption with SSL or authentication.
Role Based Authentication per queue
In order to have role based authentication inside our queue server you need to setup HornetQ with these directives.
you can restrict the access to particular queue (read/write) or even prevent the creation, deletion of new queues, with a basic role based access control.
<security-settings>
<security-setting match="#">
<permission type="send" roles="MyRole"/>
<permission type="consume" roles="MyRole"/>
<permission type="createNonDurableQueue" roles="MyRole"/>
<permission type="deleteNonDurableQueue" roles="MyRole"/>
</security-setting>
</security-settings>
The match element tells to hornetq which queue address is interested in this authentication setting. To better understand how to setup this parameter, refer to the official
HornetQ documentation.Once the queue name is matched, your client has to be in the defined role in order to perform the desired operation. Usually the best practice is to leverage the security-domain element to validate the role, similar to what can be done in the Webservices or the Remoting subsystem.
Security of JNDI Lookup for initialContext setup
When a JNDI lookup is used to get the initialContext, the security aspect of that operation is managed by the Remoting subsytem.
The Messaging subsystem communicates with your client only after the JNDI lookup is successful.
Refer to the Remoting subsystem section for more information on how to secure it.
Cluster Authentication
If a messaging cluster is used, authentication must be in place to prevent unauthorized nodes joining the cluster pool.
Setup you password in the <hornetq-server> element:
<hornetq-server>
...
<cluster-user>myuser</cluster-user>
<cluster-password>${jboss.messaging.cluster.password:mypass}</cluster-password>
</hornetq-server>
Properties at startup
It is possible to set up the password and the username as java properties, I.E. jboss.messaging.cluster.password.
This way you may simplify the XML configuration management
Management Interfaces
HTTP API
Default HTTP Interface Security
The web interface uses the HTTP API to perform tasks. Please refer to the HTTP API for security related operations
JGroups Subsystem
The JGroups subsystem is part of the default JBoss AS 7.2 HA (High Availability) configuration. JGroups is used by other subsystems (I.E. Infinispan) to share data across clusters of Jboss AS.
Unfortunately, the security subsystem is not integrated with the JGroups subsystem. For this reason, you must set up several configuration parameters that may look redundant.
Enable Encryption
The ENCRYPT protocol uses a keystore in order to encrypt the communication layer of all the other protocols below it.
Before configuring the AS, you must create another keystore to use specifically in JGroups.
Unfortunately, JGroups does not support the keystores generated with the standard JDK keytool. You must create your custom keystore with a java file called KeyStoreGenerator which is included in the demo package of JGroups.
java -cp /your/path/to/jboss/modules/system/layers/base/org/jgroups/main/JGroups-version.jar org.jgroups.demos.KeyStoreGenerator --alg AES --size 128 --storeName FILENAME --storePass PASSWORD --alias MyKey
This example will create a keystore named as specified in FILENAME with the password specified in PASSWORD and a key named MyKey, feel free to experiment with different configuration as described in the JavaDOC of this class.
Then include the ENCRYPT protocol in the standalone-full-ha of your JBoss AS instance.
<stack name="udp">
<transport type="UDP" socket-binding="jgroups-udp" diagnostics-socket-binding="jgroups-diagnostics"/>
<protocol type="PING"/>
<protocol type="MERGE2"/>
<protocol type="FD_SOCK" socket-binding="jgroups-udp-fd"/>
<protocol type="FD"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="BARRIER"/>
<protocol type="pbcast.NAKACK"/>
<protocol type="UNICAST2"/>
<protocol type="pbcast.STABLE"/>
<protocol type="ENCRYPT">
<property name="encrypt_entire_message">true</property>
<property name="sym_init">128</property>
<property name="sym_algorithm">AES/ECB/PKCS5Padding</property>
<property name="asym_init">512</property>
<property name="asym_algorithm">RSA</property>
<property name="keyPassword">YOURKEYSTOREPASSWORD</property>
<property name="keyStoreName">path/to/keystore</property>
<property name="alias">MyKey</property>
<property name="storePassword">YOURTRUSTSTOREPASSWORD</property>
</protocol>
<protocol type="pbcast.GMS"/>
<protocol type="UFC"/>
<protocol type="MFC"/>
<protocol type="FRAG2"/>
</stack>
<stack name="tcp">
<transport type="TCP" socket-binding="jgroups-tcp" diagnostics-socket-binding="jgroups-diagnostics"/>
<protocol type="MPING" socket-binding="jgroups-mping"/>
<protocol type="MERGE2"/>
<protocol type="FD_SOCK" socket-binding="jgroups-tcp-fd"/>
<protocol type="FD"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="BARRIER"/>
<protocol type="pbcast.NAKACK"/>
<protocol type="UNICAST2"/>
<protocol type="pbcast.STABLE"/>
<protocol type="ENCRYPT">
<property name="encrypt_entire_message">true</property> <!-- Encrypt the entire message sent -->
<property name="sym_init">128</property> <!-- This is the size of the key in bits -->
<property name="sym_algorithm">AES/ECB/PKCS5Padding</property> <!-- Symmetric encryption algorithm used -->
<property name="asym_init">512</property> <!-- This is the size of the asymmetric key in bits -->
<property name="asym_algorithm">RSA</property> <!-- Asymmetric encryption algorithm used -->
<property name="keyPassword">YOURKEYSTOREPASSWORD</property> <!-- Keystore password -->
<property name="keyStoreName">path/to/keystore</property> <!-- the path to the keystore, you can use jboss expansion i.e. {jboss.mykeystore.path} -->
<property name="alias">MyKey</property> <!-- The name of the key generated -->
<property name="storePassword">YOURTRUSTSTOREPASSWORD</property> <!-- Trustore password -->
</protocol>
<protocol type="pbcast.GMS"/>
<protocol type="UFC"/>
<protocol type="MFC"/>
<protocol type="FRAG2"/>
</stack>
It is preferable in big clusters, to use asymmetric encryption, in that configuration the keystore does not need to be copied across the nodes of the cluster. However, there are several differences and considerations to put in account when choosing symmetric or asymmetric encryption. Read more about it here
You can move the ENCRYPT element up and down trough the protocols stack, this will configure the subsystem to encrypt only the protocols below the ENCRYPT element.