【问题标题】:Can I avoid putting key store password on command-line with JSSE?我可以避免使用 JSSE 将密钥库密码放在命令行上吗?
【发布时间】:2011-03-09 20:55:57
【问题描述】:

我们使用的是 Maven 2,并且有一个使用 SSL 客户端身份验证保护的 Maven 存储库管理器。为了让 Maven 访问存储库,必须将以下系统属性传递给 Java:

javax.net.ssl.trustStore=trust.jks
javax.net.ssl.trustStorePassword=<trustPass>
javax.net.ssl.keyStore=keystore.p12
javax.net.ssl.keyStoreType=pkcs12
javax.net.ssl.keyStorePassword=<keyStorePass>

查看mini-guide了解更多详情。

为了在 Maven 中设置这些系统属性,我必须使用 MAVEN_OPTS 环境变量(或者直接在命令行中传递它们)。无论哪种方式,当 Maven 实际执行时,所有这些属性都对系统上的其他用户可见(通过 ps),包括我的密钥库密码。

有没有办法设置这些属性,使密码不会暴露在命令行上?

【问题讨论】:

  • 你在一个特定的平台上运行吗?
  • 我对 Maven 一无所知,但你不能以某种方式从文件中读取属性吗?
  • @erickson 我们使用 linux (ubuntu) 和 Mac 作为开发平台。
  • @Paulo 如果我可以控制 Maven 的 http 客户端,我可以从文件中读取属性并以编程方式设置属性。如果不写插件,我认为这是不可能的,也许你用插件也无法做到。
  • 在 Mac OS X 上,您可以将密钥对放在 Apple“钥匙串”中,然后授予 maven 对钥匙串的访问权限。在此处查看一些相关信息:*.com/questions/727812/…。 Windows 与 Java 密钥存储有类似的桥接,但我还没有为 Linux 找到令人满意的解决方案。

标签: java ssl maven jsse


【解决方案1】:

OSX

我在 OSX 上提出的解决方案如下.mavenrc。它使用 python 脚本访问钥匙串中的密码以打开客户端证书,然后使用该随机密码生成一个随机密码和一个临时证书。

将其放入~/.mavenrc 并将您的客户端证书添加到 OSX 钥匙串。确保并将 MAVEN_CLIENT_CERT 设置为您的客户端证书的位置。

~/.mavenrc

export MAVEN_CLIENT_CERT=<PATH.TO.CLIENT.CERTIFICATE>

# Retrieve secret from keychain
export SECRET=$(python <<END
from subprocess import Popen, PIPE
import re, sys, os

passlabel = os.environ.get("MAVEN_CLIENT_CERT", None)

p = Popen(['security', 'find-generic-password', '-l',passlabel,'-g'], stdout=PIPE, stderr=PIPE, stdin=PIPE)

sys.stdout.write(re.compile('password:\\s"(.*)"').match(p.stderr.read()).group(1))
sys.exit(0)
END)

TMPDIR=/tmp
TMPTMPL=mvn-$(id -u)-XXXXXXXXXX
PASSPHRASE=$(openssl rand -base64 32)
export PASSPHRASE TMPDIR

pemfile=$(mktemp $TMPDIR/$TMPTMPL)
openssl pkcs12 -in $MAVEN_CLIENT_CERT -passin env:SECRET -out $pemfile -passout env:PASSPHRASE
p12file=$(mktemp $TMPDIR/$TMPTMPL)
openssl pkcs12 -export -in $pemfile -out $p12file -passin env:PASSPHRASE -passout env:PASSPHRASE

sh -c "while kill -0 $$ 2>/dev/null; do sleep 1; done; rm -f $pemfile; rm -f $p12file;" &

MAVEN_OPTS="$MAVEN_OPTS -Djavax.net.ssl.keyStore=$p12file -Djavax.net.ssl.keyStoreType=pkcs12 -Djavax.net.ssl.keyStorePassword=$PASSPHRASE"

Linux

在 Linux 上,以下 .mavenrc 将与 gnome 密钥环一起使用(确保将证书密码添加到您的登录密钥环并设置 id 变量KEYRING_ID):

~/.mavenrc

MAVEN_CLIENT_CERT=<PATH.TO.CLIENT.CERTIFICATE>

export KEYRING_NAME="login"
export KEYRING_ID=<KEYRING.ID>

# Try to get secret from the gnome keyring 
export SECRET=$(python <<END
import sys, os
# Test for gtk
try:
  import gtk #ensure that the application name is correctly set
  import gnomekeyring as gk
except ImportError:
  gtk = None
if gtk:
  id = os.environ.get("KEYRING_ID", None)
  name = os.environ.get("KEYRING_NAME", None)
  try:
    if id:
      info = gk.item_get_info_sync(name, int(id))
      attr = gk.item_get_attributes_sync(name, int(id))
      sys.stdout.write(str(info.get_secret()))
    else:
      params = {}
      types = {'secret': gk.ITEM_GENERIC_SECRET, 'network': gk.ITEM_NETWORK_PASSWORD, 'note': gk.ITEM_NOTE}
      eparams = os.environ.get("KEYRING_PARAMS", None)
      etype = os.environ.get("KEYRING_ITEMTYPE", None)
      if eparams and etype:
        list = eparams.split(',')
        for i in list:
          if i:
            k, v = i.split('=', 1)
            if v.isdigit():
              params[k] = int(v)
            else:
              params[k] = v
        matches = gk.find_items_sync(types[etype], params)
        # Write 1st out and break out of loop. 
        # TODO: Handle more then one secret.
        for match in matches:
          sys.stdout.write(str(match.secret))
          break
    sys.exit(0)
  except gk.Error:
    pass
sys.exit(1)
END
)

TMPDIR=/dev/shm
TMPTMPL=mvn-$(id -u)-XXXXXXXXXX
PASSPHRASE=$(openssl rand -base64 32)
export PASSPHRASE TMPDIR

pemfile=$(mktemp $TMPDIR/$TMPTMPL)
openssl pkcs12 -in $MAVEN_CLIENT_CERT -passin env:SECRET -out $pemfile -passout env:PASSPHRASE
p12file=$(mktemp $TMPDIR/$TMPTMPL)
openssl pkcs12 -export -in $pemfile -out $p12file -passin env:PASSPHRASE -passout env:PASSPHRASE

sh -c "while kill -0 $$ 2>/dev/null; do sleep 1; done; rm -f $pemfile; rm -f $p12file;" &

MAVEN_OPTS="$MAVEN_OPTS -Djavax.net.ssl.keyStore=$p12file -Djavax.net.ssl.keyStoreType=pkcs12 -Djavax.net.ssl.keyStorePassword=$PASSPHRASE"

【讨论】:

  • 试试这个:运行 Maven,然后 ps -ef -- 如果我没记错的话,你的密钥库密码将是传递给 java 的参数。这不是一个很好的解决方案...
  • 我认为您可能误读了解决方案。证书和密码是临时的。 mvn 运行时,您的实际密码不可见。
  • 你是对的,它在 openssl 命令运行时可见,但在 Maven 运行时不可见。我想这更好,因为 openssl 应该更快?尽管如此,您必须将未混淆的实际证书密码放在 some 命令行上,这(恕我直言)仍然不是很好。
  • 我完全同意,但我认为没有 maven 本身的一些支持,没有其他好的解决方案。
  • 这不是 技术上 Maven 的错,只是 Java 在为具有核心/非主流的客户端证书提供强大的凭证存储/检索方面落后于时代盒子类。 Apple Java 有KeychainStore 提供程序,Microsoft 与WINDOWS-MY 提供程序很好地集成在一起——在这一点上,我认为唯一的缺点是没有特定的 Linux 组件觉得有必要弥补这一不足并提供一个类似的提供程序例如,gnome-keyring
【解决方案2】:

在 OSX 上,您可以将您的钥匙串用作密钥库(据我所知,仍然存在一个错误,所以它只有在只有一个“身份”时才有效,即证书+私钥的组合)。

请使用它,使用-Djavax.net.ssl.keyStore=NONE-Djavax.net.ssl.keyStoreType=KeychainStore-Djavax.net.ssl.keyStorePassword=-

然后,钥匙串会在需要时提示您批准使用私钥。

【讨论】:

    【解决方案3】:

    您可以在 Maven 设置文件中定义这些属性。它们的访问方式与您在命令行上提供它们时的方式相同。这是您的 Maven 设置文件的示例:

    <profiles>
        <profile>
            <id>repo-ssl</id>
            <properties>
                <javax.net.ssl.trustStore>trust.jks</javax.net.ssl.trustStore>
                <javax.net.ssl.trustStorePassword>SET_TRUSTSTORE_PASSWORD</javax.net.ssl.trustStorePassword>
                <javax.net.ssl.keyStore>keystore.p12</javax.net.ssl.keyStore>
                <javax.net.ssl.keyStoreType>pkcs12</javax.net.ssl.keyStoreType>
                <javax.net.ssl.keyStorePassword>SET_KEYSTORE_PASSWORD</javax.net.ssl.keyStorePassword>
            </properties>
        </profile>
    </profiles>
    
    <activeProfiles>
        <activeProfile>repo-ssl</activeProfile>
    </activeProfiles>
    

    虽然我没有做与您尝试相同的事情,但我在处理机密时使用了相同的技术。

    【讨论】:

    • 这似乎不起作用。对 javax.net.ssl.* 的 System.getProperty() 调用(使用 exec:java)返回 null 时,如您所示定义属性。
    • @kldavis4 它假定程序将始终通过 Maven 运行。而是一个限制性假设。
    • OP 表示在 Maven 中使用,这就是我提出解决方案的原因。
    【解决方案4】:

    是的,您可以在获取初始 SSLContext 之前在代码中使用 System.setProperty(),或者您可以按照 JSEE 参考指南中的示例描述创建自己的 KeyManager 等的痛苦和痛苦。

    【讨论】:

      最近更新 更多