【问题标题】:Where to keep p12 file securely on App Engine?将 p12 文件安全地保存在 App Engine 上的什么位置?
【发布时间】:2014-08-21 17:41:13
【问题描述】:

在 App Engine 上,我需要一个 p12 文件来创建签名网址:

https://developers.google.com/storage/docs/accesscontrol#Signing-Strings

Google 没有描述保存此文件的最佳做法。

我可以使用 WEB-INF 目录来存储文件吗?然后它将成为源代码的一部分,并与打开它的密码一起保存。

这里有哪些最佳做法?还是其他方法?

--

性能怎么样?一遍又一遍地加载文件是否有效? App Engine 是否会跨调用(在同一实例上)自动缓存文件?或者我是否需要使用 servlet 加载文件一次,然后以某种方式将其保存在静态变量中?有没有更好的方法来实现这一点,比如将文件存储在数据存储记录中,然后将其保存在内存缓存中?这种方法有多安全?应该不会吧?

【问题讨论】:

  • 通常我使用 WEB-INF(无法从外部源访问)或类路径(类文件夹,存储已编译的 java 的位置)

标签: security google-app-engine signing


【解决方案1】:

特别是在 App Engine 中,文件存储存在许多不寻常的安全限制。我发现安全存储资源的最佳位置是使用捆绑包本身。如果您使用的是由 appengine maven 框架项目生成的默认 Maven 设置,这就像将文件放在适当的资源目录中一样简单

一旦 p12 位于正确的位置,您就需要使用类加载器的 GetResourceAsStream 函数来加载它。然后在构建 GoogleCredentials 时,不要使用记录在案的 setServiceAccountPrivateKeyFromP12File() 函数,而是使用 setServiceAccountPrivateKey() 函数并传入您刚刚构建的 PrivateKey。

此外,您很可能不想将任何此功能用于实时 appengine 实例,因为 Appengine 已经为您提供了在这种情况下更易于使用的 AppIdentityCredentials 函数,因此您可能希望检测您的应用是否处于生产模式,仅在使用 localhost 进行测试时使用 ServiceAccount。

将所有这些函数放在一起会产生以下对我有用的函数:

public static HttpRequestInitializer getDefaultCredentials() throws IOException
  {
      List<String> scopes = Arrays.asList(new String[] {DEVSTORAGE_FULL_CONTROL});
      if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Production)
          return new AppIdentityCredential(scopes);
      else
      {

          GoogleCredential credential;

          try {
              String p12Password = "notasecret";

              ClassLoader classLoader = ServiceUtils.class.getClassLoader();

              KeyStore keystore = KeyStore.getInstance("PKCS12");
              InputStream keyFileStream = classLoader.getResourceAsStream("key.p12");

              if (keyFileStream == null){
                  throw new Exception("Key File Not Found.");
              }

              keystore.load(keyFileStream, p12Password.toCharArray());
              PrivateKey key = (PrivateKey)keystore.getKey("privatekey", p12Password.toCharArray());

              credential = new GoogleCredential.Builder()
                      .setTransport(HTTP_TRANSPORT)
                      .setJsonFactory(JSON_FACTORY)
                      .setServiceAccountId("YOUR_SERVICE_ACCOUNT_EMAIL@developer.gserviceaccount.com")
                      .setServiceAccountPrivateKey(key)
                      .setServiceAccountScopes(scopes)
                      .build();
          } catch (GeneralSecurityException e) {
              e.printStackTrace();
              return null;
          } catch (Exception e) {
              e.printStackTrace();
              return null;
          }

          return credential;

      }

  }

【讨论】:

  • [谢谢蒂姆。这是一个比较老的问题,但是当我在几周后回到服务器开发时,我肯定会再次研究这个问题。然后我会评论。]
  • 您在生产环境中获取凭据的建议很酷,但我不能使用它,因为我需要 PKCS12 进行 url 签名,而不是 Google 凭据。我试图实现您建议的静态资源部分,但遇到了两个问题:在我的文件夹结构中看不到 Resources 文件夹(这是一个基于演示的项目,Android Studio),并且 ServiceUtils 类没有存在。我正在阅读可以配置资源文件夹,并且可以在 appengine-web.xml 中告诉应用引擎我想将 .p12 文件视为静态文件,因此可以解决此问题。有什么想法吗?
  • 基于这个想法,我将 .p12 文件留在了当前位置,但添加了 到 appengine-web.xml,根据cloud.google.com/appengine/docs/java/config/…,它将从静态文件服务器为 p12 提供服务。不过,我看不出成本有任何降低。
  • 啊,很好,我很高兴你能成功。我同意,我提到的方法主要关注安全性,而不是访问效率。我很抱歉错过了你问题的后半部分。我也同意 memcache 是一个不好的地方,因为 Google 不保证 memcache 的安全性。您是否尝试过将 .p12 加载功能放在单例中?这样,至少您通常每个实例只加载一次文件。当然,如果您运行大量实例,这仍然可以加起来,但它可能会为您节省一些周期。
  • 哇,太棒了,蒂姆。单身是个好主意。我最终只使用了一个私有静态变量作为我在 null 时加载的密钥,并获得了超过 400% 的性能提升。通过所有这些优化,我可以将 CPU 时间从 250 毫秒减少到近 50 毫秒。签名网址仍然很昂贵,但现在好多了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多