The problem of eliminating clear text passwords from all media has a long history of failure and success. In the first years of the HTTP protocol, designers, despite existence of asymmetric encryption, decided not to use anything. Later, having been burned by cleartext passwords, they added base64 encoding. Which, as one may guess, did not fool anyone in the business of retrieving those passwords.
Luckily - Netscape introduced the SSL tunnel for HTTP, which was widely and enthusiastically accepted. This eliminated some of the threats, but had nothing to do with protecting the password storage. Most systems that interact with an authenticated service over HTTP still have to figure out a way to store these credentials. The alternative is for the serivce in question to use something like OAUTH or a distributed ticketing system (ala Facebook or Twitter). But, for most systems that need to interact with an authenticate service of HTTP this is a serious problem. If you need to deploy to an authenticated repository manager like Nexus, how do you avoid putting your password into your build?
The Problem with settings.xml
Maven repository access uses a plaintext password over HTTP (preferably HTTPS) and most people have a situation when passwords are kept in the open in the settings.xml file. If you use settings.xml as designed, you'll have a clear security vulnerability if your settings.xml is publicly accessible. There was a long discussion on the codehaus confluence about this issue last August.
settings.xml contains two very distinct types of content serving two distinct purposes: the servers section really stores credentials while the rest of the file is all about profile customizations. The servers section contains all the private data, while the rest is more or less open. If you are using the settings.xml file as documented and as recommended, you'll have a situation where one part of the file should not be widely distributed and the other part of the file must be widely distributed for a build to work. This creates an inconvenience as some manual work is required to share your organization's setting.xml between developers. If you check a global settings.xml into Subversion, do you check in the passwords as well? If every potential attacker knows that the ~/.m2/settings.xml contains sensitive credential information, is this really an acceptable security risk?
Having such a file on your single-user laptop or private machine is likely an acceptable (but not ideal) risk. But, putting this file on a shared box like a Continuous Integration or shared build machine where any individual with malicious intent can compromise your repositories in no time is totally unacceptable.
To mitigate these risks, it's recommended to store all private data in ~/.m2/settings.xml and all the rest - in ${maven.home}/conf/settings.xml. But here is the problem again - if you upgrade maven and put it into another folder, you have to also move the global settings.xml. Or - if switching between several versions of maven - having to maintain all those separate settings.xml files in-sync presents a major inconvenience, to say more.
New Feature: Maven Settings Password Encryption
To address these issues, I added password encryption to maven 2.1.x trunk. This is a very straightforward change, which I ported from a change I made to maven 2.0.8 in 2007 but never committed before. This feature checks the passwords when in memory, and decrypts them if they have the pattern {xxx}. I also provided a CLI to encrypt any string.
Details: the encryption is using JDK's AES 128 cipher and PBE SHA256 key preparation, which I took from a very interesting not-yet-commons-ssl project - APL-2.0 based.
To use it, you need to first generate a master password - with:
java -jar ${maven.home}/lib/maven-uber.jar \
org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher -m
It will ask for master password and will output the encrypted version of it. Store this string in ~/.m2/settings-security.xml:
<settingsSecurity>
<master>{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ=}</master>
</settingsSecurity>
After that - you can encrypt regular passwords and store them in settings.xml. Run:
java -jar ${maven.home}/lib/maven-uber.jar \
org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher -p
Supply the password and then store the output string in settings:
<server>
<id>my.server</id>
<username>foo</username>
<password>{COQLCE6DU6GtcS5P=}</password>
</server>
That's all - you can start deploying to the server right away - Maven will decrypt it on the fly. You can stop worrying about mvn help:effective-settings or release POM exposing your passwords - they show up encrypted there.
Summary and Best Practices
Remember - the weak spots in this schema are:
- The master password is only propected by the Operating System's access rules: always restrict access to ~/.m2 - make it readable and by owner only
- The server password is decrypted in memory and consumed by wagon provider, so if somebody can scan the memory or intercept the wire transmission (if it's not encrypted), they can compromise your server.
To address the use case, where several people share one account, or you'd like to have security above OS access - you can use master password relocation feature - use xml like:
<settingsSecurity>
<relocation>/Volumes/mySecureUsb/secret/settings-security.xml</relocation>
</settingsSecurity>
and store the real master password on a usb drive. In this case - only a person with that drive can deploy to the server.
Written by Oleg Gusakov
Oleg is a former Chief Architect at Sonatype. He now works as an engineer at TripActions, a business travel platform that empowers companies and travelers to show up and create growth.