Cryptography 在源代码中存储密码

Cryptography 在源代码中存储密码,cryptography,passwords,password-protection,Cryptography,Passwords,Password Protection,我现在已经读过几个地方,它们基本上建议不要在源代码中存储密码,我理解其中的原因 我有两个应用程序:一个用于加密,一个用于解密。数据被加密到服务器上的文件中;该文件在客户端机器上下载和解密,然后由一个非我的专有应用程序处理。数据是敏感的,理想情况下只能由处理应用程序访问。 目前我使用的是对称密钥算法,因为数据足够大。密码是以字符串的形式硬编码到源代码中的——我知道,这有几个原因 我想知道的是存储密码的最佳方式是什么?我的想法是使用非对称密钥算法,例如RSA,仅用于密码,但我不知道如何做到这一点,以

我现在已经读过几个地方,它们基本上建议不要在源代码中存储密码,我理解其中的原因

我有两个应用程序:一个用于加密,一个用于解密。数据被加密到服务器上的文件中;该文件在客户端机器上下载和解密,然后由一个非我的专有应用程序处理。数据是敏感的,理想情况下只能由处理应用程序访问。 目前我使用的是对称密钥算法,因为数据足够大。密码是以字符串的形式硬编码到源代码中的——我知道,这有几个原因


我想知道的是存储密码的最佳方式是什么?我的想法是使用非对称密钥算法,例如RSA,仅用于密码,但我不知道如何做到这一点,以及它在我的场景中是否有意义。我不想引入另一个文件进行分发。我对反编译知之甚少,但我认为在客户端应用程序中实现PBKD也会带来同样的问题。你可以告诉我,加密术对我来说是新的,使用这个伟大的论坛。

而不是将明文密码存储在源代码中,并检查是否可以将加密密码存储在源代码硬编码中

然后用户可以输入密码,代码对密码进行加密,并将加密结果与存储的加密值进行比较,以查看密码是否匹配。然后使用输入的密码(而不是加密密码)对数据进行加密/解密

所使用的加密应努力将加密密码反转为明文密码,这是很难/不可能的

例如:

您选择加密/解密密码这是我的密码1当前在源代码中。 您可以使用示例SHA-256对密码进行加密,并在源代码9845735B525FA70B2651975022A44BE268AF1D4DEFADBA9AB2A0301E079534C中对其进行硬编码。 加密/解密应用程序提示输入密码。 用户输入密码。 应用程序计算输入密码的SHA-256,并将结果与9845735B525FA70B2651975022A44BE268AF1D4DEFADBA9AB2A0301E079534C进行比较 如果它与数据匹配,则使用输入的密码进行加密/解密,这是我的密码1,使用的是您已经存在的代码。 如果不匹配,请给出一个错误。 黑客获取您的源代码并访问哈希9845735B525FA70B2651975022A44BE268AF1D4DEFADBA9AB2A0301E079534C和您使用的算法。但他需要密码这是我的密码1密码来解密数据。他可以反转或强制执行哈希,但这需要努力和时间

一个人可以使用种子等,但保密又是同样的问题


它可能不是最安全的,我不是专家,但它比在源代码中有这是我的密码要好

请不要在源文件中使用对称键。您可以在不引入其他文件的情况下使用RSA。与对称密钥相反,公钥可以在源代码中硬编码而不存在任何安全问题,如果可以保证源文件的完整性。再说一次,如果有人设法改变它,解密将不起作用,或者有人在中间进行MITM攻击,你不会知道

警告

这种方法易受MITM攻击的影响。一个适当的对策是对数据进行签名,但随后您将无法处理密钥,这实际上是一个单独的问题。 关键点不是永久的,您生成的关键点对需要不时旋转。 使键足够大,至少2048位。 撤销需要由您手动完成。如果您需要一个更自动化的解决方案,考虑查看PKI和OSCP响应者有无订书钉。 如果发送的数据很大,RSA操作将很长。 好了,别碍事了,我们开始吧。示例代码完全使用JDK 8编写

首先,生成一个密钥对。这需要执行一次或每次旋转:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
KeyPair keyPair = kpg.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();

byte[] pubEnc = publicKey.getEncoded();
byte[] privKeyEnc = privateKey.getEncoded();

System.out.println(Base64.getEncoder().encodeToString(pubEnc));
System.out.println(Base64.getEncoder().encodeToString(privKeyEnc));
假设公钥是我生成的实际密钥,不要使用这些:

private static final String PUBLIC_KEY_BASE64 = 
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCGue
5TCdPJt08w7crbvWjfcSUy/xXjzjjjjPDP7D8PNSnn
CUeNcGWsR/Pd3eoBjmrAy/4Rl8JlHylRry8pX7Zpcz
iQB8wWQdpkSoArjeu4taeFn/45+eg4J5mzmIzFG9F5
wF7N+SeSvtq3E3Q0mtJRRZZJYgNkFmeDuOQjljJVZw
IDAQAB";
私钥是:

private static final String PRIVATE_KEY_BASE64 = 
"MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAg
EAAoGBAIa57lMJ08m3TzDtytu9aN9xJTL/FePOOOOM
8M/sPw81KecJR41wZaxH893d6gGOasDL/hGXwmUfKV
GvLylftmlzOJAHzBZB2mRKgCuN67i1p4Wf/jn56Dgn
mbOYjMUb0XnAXs35J5K+2rcTdDSa0lFFlkliA2QWZ4
O45COWMlVnAgMBAAECgYBAWTIRi1ISuHEkh48qoS8j
+eCwmNGVuvvFA55JUSdVVikrZm08iwCk5sD9qW6JS8
KFT2mMcZWxws5za171PffbeHoIFaNI5n5OXJa4meZA
cgl4ae5su89BjvfzDF2gsnBHwLpgsT0aVdIDQ5BGtL
WzRwZCogY6lZhBOQZAaNFYIQJBALr2+kT+pkSlxrrR
tMxK7WL+hNO7qOIl/CTBuAa6/zTtoEjFMFQBY//jH+
6iabHDfKpaFwh6ynZTXZsb7qIKOM8CQQC4eRAH1VEo
iofZNnX3VjiI5mLtV8rc8Jg+wznN+WFnwdNoLK8y9t
EcuKxg3neIJAM70D6l0IhBfza1QAqQh4/pAkA5vyLZ
wJV2SoWxGihvmQztMJOyGho1j2nrqHHAkm1U2bhSAa
XFrJBIbsxkFoHyx+BvdVf75IE4PtOAnwX7wpB9AkBQ
7CKBHS2N+D8hpQdYqcUBIPdyoFmIVC6lEaTw2x3Ekz
027KsqUyVmUQilMdIDsbCNc4uX14N+H90S43X+8sjJ
AkAKsvRbZ0Au9JytSRKSB7vYl37283zHoQ5jyYUE7x
g7C6nWSl1GEa6khZ47hFAj9C2bdLJ6GtjTleFsVCsR
LUoG";
出于格式化原因,上面的键是换行的

假设args[0]在黎明时遭到攻击!您的客户看起来是这样的:

public static void main(String[] args) throws Exception {
   byte[] pubKey = Base64.getDecoder().decode(PUBLIC_KEY_BASE64);
   PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(pubKey));

   Cipher cipher = Cipher.getInstance("RSA");
   Cipher.init(Cipher.ENCRYPT_MODE, publicKey);
   String encryptedData = Base64.getEncoder().encodeToString(cipher.doFinal(args[0].getBytes("UTF-8")));
   System.out.println("Encrypted data is: " + encryptedData);
}
输出:加密数据为: cDoPpQYc6qibrBl5jdENcV+g6HslQDlo9potca5rQxecnxR3Bd/e1T0njqUMACl7x7AG3foGxqZyyUIMrOVXcnw/ux7BgQcg+RDZhSVFQAd5kUGI96pw8WtDVo1N1+WEFAPHK9CPWUKUXTWR0T27N+W0VHFCQNTEGHOFT8U9O=

服务器:

public static void main(String[] args) throws Exception {
  byte[] privKey = Base64.getDecoder().decode(PRIVATE_KEY_BASE64);
  PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privKey));

  Cipher cipher = Cipher.getInstance("RSA");
  cipher.init(Cipher.DECRYPT_MODE, privateKey);
  byte[] encryptedData = Base64.getDecoder().decode(args[0]); 
  byte[] decryptedData = cipher.doFinal(encryptedData);
  System.out.println("Decrypted message was: " + new String(decryptedData, "UTF-8"));

}
输出:解密的消息是:黎明攻击

JDK的RSA实现有一个很酷的地方,那就是它使用了来自PKCS1的最佳非对称加密填充OAEP,其效果是,即使相同的消息在每次加密中看起来也会不同

正如前面的评论者所提到的,在没有看到全部情况的情况下,可能还有其他安全问题需要解决。但无论如何,我认为这种方法比使用symmetrica更好
l密钥,仍然可以与此加密方案一起使用。然后你会得到所谓的混合密码系统,但是有API可以为你做到这一点。

那么你希望你的程序拥有数据,但用户没有?然后根本不要将数据发送给客户机。在服务器上进行处理。openSSL将是一个很好的密码学库选项。请阅读本教程,了解如何实现openSSL以及openSSL在这里有何帮助?对,一点也不。[顺便说一句,你是否错过了已经使用加密+?]不可能对用户保密用户计算机上的数据。用户计算机上的一个程序有一个密钥,不可能对明文保密。我们并不知道你试图防御的威胁,所以很难说你应该做什么以及如何做。在进一步讨论之前,您可能应该访问OWASP的John Steven并访问他们。RSA不是散列。MD5一点也不安全。c如果所有内容都在客户端设备上,则无需反转哈希。比那容易多了。d如果散列是加密的,而密钥也在程序中,为什么还要加密?@deviantfan我理解你的意思,并更新了我的答案,使我想说的更清楚,这有帮助吗?不太有帮助,因为像你在最后一句中描述的加密不存在,如果是加密,密钥必须在某个地方,正如前面所说的,它根本没有帮助,因为攻击者不需要逆转一些不可逆转的东西。一个难以逆转的东西确实存在,比如SHA-256,是的,黑客可以对其进行暴力攻击,但数据是否比暴力攻击的时间更有价值?SHA-256算法生成一个几乎唯一、固定大小的256位32字节散列。散列是一个单向函数,它不能被解密回来。种子会让它更安全,但它真的需要吗。。。黑客在能够解密数据之前,必须反转哈希或暴力破解密码,否则如何?但SHA256不是加密,它没有密码/密钥来加密其他数据。。。几乎是独一无二的完全是胡说八道;每个可能的散列值都有无限可能的明文。。。播种一些要加密的数据也是无稽之谈。。。请,只是了解更多关于这方面的东西,这是密码学的最低基础。很好的例子,谢谢你的建议!我认为在我的例子中,情况正好相反:服务器只加密,客户端只解密,没有其他通信。解密后的数据在本地机器上从另一个进程(不是我的进程)进行处理。考虑到这一点,私钥不是必须与客户端在一起吗?这很好,除了在错误的人手中,我想限制对纯文本的访问。由于客户机-服务器模型中通常固有的不对称性—许多客户机和少数服务器,因此仅加密发送给客户机的数据听起来是个坏主意。私钥必须分发到您通常无法控制的客户机环境中。如果你把它放在源代码中,只有一个键,这使得它非常容易受到攻击。如果是这样的话,我会考虑使用Diffie-Hellman而不是RSA。你仍然容易受到MITM攻击,但另一方面,你会得到PFS完美的前向保密。亲爱的,我会调查的。