简体   繁体   English

以可逆形式存储密码

[英]Storing Passwords in reversible form

I have a PHP app that needs to run bash scripts, and provide a username & password (for remote systems). 我有一个PHP应用程序需要运行bash脚本,并提供用户名和密码(用于远程系统)。 I need to store these credentials somewhere that is accessible by my PHP (web) app. 我需要将这些凭据存储在我的PHP(Web)应用程序可访问的某个位置。 The logical place is the database (currently MySQL, but will be agnostic). 逻辑位置是数据库(目前是MySQL,但是不可知)。 The problem with the "standard" way of hashing and storing the credentials, is that it is not reversible. 散列和存储凭证的“标准”方式的问题在于它是不可逆的。 I have to be able to get the credentials out as unencrypted clear text, to be able to insert the data into bash scripts. 必须能够以未加密的明文形式获取凭证,以便能够将数据插入到bash脚本中。

Does anyone have any suggestions for a secure way to go about this ? 有没有人有任何建议可以安全地解决这个问题?

I thought maybe PKI'ing the credentials, and storing the result in the DB. 我想也许是PKI的凭证,并将结果存储在DB中。 Then use the private key to unencrypt (PHP can do that). 然后使用私钥解密(PHP可以做到这一点)。 Store the scripts to do this outside the web root. 存储脚本以在Web根目录外执行此操作。

Any thoughts much appreciated. 任何想法都非常感激。

First, to state the (hopefully) obvious, if you can in any way at all avoid storing usernames and passwords do so; 首先,说明(希望)明显,如果你可以以任何方式避免存储用户名和密码这样做; it's a big responsibility and if your credential store is breached it may provide access to many other places for the same users (due to password sharing). 这是一项重大责任,如果您的凭据存储被破坏,它可能会为同一用户提供访问许多其他地方(由于密码共享)。

Second, if you must store credentials prefer rather to stored passwords using a non-reversible, salted cryptographic hash, so if you data is compromised the passwords cannot easily be reverse-engineered and there's no need to store a decryption key at all. 其次,如果您必须使用不可逆的盐渍加密哈希来存储凭证,而不是存储密码,那么如果您的数据受到损害,则密码不能轻易地进行逆向工程,并且根本不需要存储解密密钥。

If you must store decryptable credentials: 如果必须存储可解密的凭据:

  1. Choose a good encryption algorithm - AES-256, 3DES (dated), or a public key cipher (though I think that's unnecessary for this use). 选择一个好的加密算法 - AES-256,3DES(过时)或公钥密码(虽然我认为这对于这种用途是不必要的)。 Use cryptographic software from a reputable trustworthy source - DO NOT ATTEMPT TO ROLL YOUR OWN, YOU WILL LIKELY GET IT WRONG. 使用来自信誉良好的可信赖来源的加密软件 - 不要试图自己动手,你可能会错误地认识它。
  2. Use a secure random generator to generate your keys. 使用安全随机生成器生成密钥。 Weak randomness is the number one cause of encryption related security failures, not cipher algorithms. 弱随机性是加密相关安全性故障的首要原因,而不是密码算法。
  3. Store the encryption/decryption key(s) separately from your database, in an O/S secured file, accessible only to your applications runtime profile. 将加密/解密密钥与数据库分开存储在O / S安全文件中,只能由应用程序运行时配置文件访问。 That way, if your DB is breached (eg through SQL injection) your key is not automatically vulnerable, since that would require access to to the HDD in general. 这样,如果您的数据库被破坏(例如通过SQL注入),您的密钥不会自动受到攻击,因为这通常需要访问HDD。 If your O/S supports file encryption tied to a profile, use it - it can only help and it's generally transparent (eg NTFS encryption). 如果您的操作系统支持与配置文件绑定的文件加密,请使用它 - 它只能提供帮助,而且通常是透明的(例如NTFS加密)。
  4. If practical, store the keys themselves encrypted with a primary password. 如果可行,请使用主密码存储密钥本身。 This usually means your app. 这通常意味着您的应用。 will need that password keyed in at startup - it does no good to supply it in a parameter from a script since if your HDD is breached you must assume that both the key file and the script can be viewed. 将需要在启动时键入的密码 - 在脚本的参数中提供它是没有用的,因为如果您的HDD被破坏,您必须假设密钥文件和脚本都可以被查看。
  5. For each credential set, store a salt (unencrypted) along with the encrypted data; 对于每个凭证集,存储salt (未加密)以及加密数据; this is used to "prime" the encryption cipher such that two identical passwords do not produce the same cipher text - since that gives away that the passwords are the same. 这用于“填充”加密密码,使得两个相同的密码不会产生相同的密码文本 - 因为这会泄露密码是相同的。
  6. If the username is not necessary to locate the account record (which in your case it is not), encrypt both the username and password. 如果没有必要使用用户名来查找帐户记录(在您的情况下不是这样),请加密用户名和密码。 If you encrypt both, encrypt them as one encryption run, eg 如果您对两者进行加密,请将它们加密为一次加密运行,例如

    userAndPass=(user+":"+pass); userAndPass =(用户+ “:” +传);
    encryptInit(); encryptInit();
    encrypt(salt); 加密(盐);
    encrypt(userAndPass); 加密(userAndPass);
    cipherText=encryptFinal(); 密文= encryptFinal();

    and store the singular blob, so that there is less occurrence of short cipher texts, which are easier to break, and the username further salts the password. 并存储奇异的blob,这样就可以减少短密码文本的出现,这些密文更易于破解,用户名还可以进一步密码。

PS: I don't program in PHP so cannot comment on suitable crypto s/w in that environment. PS:我不用PHP编程,因此无法在该环境中评论合适的加密s / w。

You'll need to look into good 2 way cryptographic methods, and my general rule of thumb is: 你需要研究好的双向加密方法,我的一般经验法则是:

If you implement your own cryptographic code you will fail. 如果您实现自己的加密代码,您将失败。

So, find a good implementation that is well verified, and utilize that. 因此,找到一个经过充分验证的良好实现,并利用它。

There is probably some good info here: 这里可能有一些很好的信息:

http://phpsec.org/library/ http://phpsec.org/library/

Check this library: PECL gnupg it provides you methods to interact with gnupg. 检查这个库: PECL gnupg它为您提供了与gnupg交互的方法。 You can easily encrypt and decrypt data, using safe public-key cryptographic algorithms. 您可以使用安全的公钥加密算法轻松加密和解密数据。

I would suggest you not store the passwords, but use passwordless ssh connection from the host to the remote system by generating a ssh key and storing your public key in the remote system's authorized_keys file. 我建议您不要存储密码,而是通过生成ssh密钥并将公钥存储在远程系统的authorized_keys文件中,使用从主机到远程系统的无密码ssh连接。 Then you would only need to establish connectivity during configuration. 然后,您只需要在配置期间建立连接。 Admittedly not quite answering your question, but storing passwords in a reversible form is a slippery slope to a security breach imho, although I am sure smarter brains than mine can make it safe. 不可否认的是,并没有完全回答你的问题,但是以可逆的形式存储密码对于安全漏洞来说是一个滑坡,尽管我确信聪明的大脑可以使它安全。

One easy way to get started is to use mysql's ENCODE() and DECODE() functions. 一个简单的入门方法是使用mysql的ENCODE()和DECODE()函数。 I don't know what algorithm is used underneath, but it's easy enough to use: 我不知道下面使用了什么算法,但它很容易使用:

INSERT INTO tbl_passwords SET encoded_pw = ENCODE('r00t', 'my-salt-string');

and

SELECT DECODE(encoded_pw, 'my-salt-string') FROM tbl_passwords;

For PHP, it is important to note that AES encryption is implemented via MCRYPT_RIJNDAEL functions. 对于PHP,重要的是要注意AES加密通过MCRYPT_RIJNDAEL函数实现的。 Don't go paying for a non-open implementation when PHP has them available. 当PHP有可用时,不要为非开放实现付费。

See the PHP page discussing available ciphers for more information. 有关更多信息,请参阅讨论可用密码PHP页面

If you go the PKI, and I would, make sure you safe guard your private keys! 如果你去PKI,我会,确保你保护你的私钥! The strong encryption provided by PKI is only as secure as your keys. PKI提供的强大加密功能与密钥一样安全。

I think you're on target. 我认为你是目标。 Look at GPG for a good, open encryption library 看看GPG是否有一个好的开放式加密库

It looks like you pretty much have two methods of doing this: 看起来你几乎有两种方法可以做到这一点:

1) Like you suggested use an encryption algorithm or algorithms which can then be decrypted and used for authentication in your scripts. 1)与您建议的一样,使用加密算法或算法,然后可以解密并用于脚本中的身份验证。 You can use the MCrypt library in PHP to accomplish this. 您可以使用PHP中的MCrypt库来完成此任务。

2) Depending on the required level of security and your script's level of vulnerability, you could use a secure hash, key, or some other hard to guess unique identifier that you can use to hijack each user's account within the confines of the script. 2)根据所需的安全级别和脚本的漏洞级别,您可以使用安全散列,密钥或其他一些难以猜测的唯一标识符,您可以使用该标识符在脚本范围内劫持每个用户的帐户。

As many stated you scenario requires that you encrypt username and password. 正如许多人所述,您需要加密用户名和密码。 I would recommend that you check out the mcrypt extension of php for encryption/decryption. 我建议您查看php的mcrypt扩展名以进行加密/解密。

I think I am going to investigate compiling a PHP script with the credentials embedded, on the fly, from the web app. 我想我将研究使用从Web应用程序中即时嵌入的凭据来编译PHP脚本。

I would ask for the credentials (for a given use), then create and compile a new PHP script, for this use only. 我会要求提供凭据(用于给定用途),然后创建并编译一个新的PHP脚本,仅供此用户使用。 That way, the script will only do what I need, and should not be "readable". 这样,脚本只会做我需要的,而且不应该是“可读的”。 I think this sounds like the safest way to do this. 我认为这听起来是最安全的方法。

Will try using Roadsend. 将尝试使用Roadsend。 http://www.roadsend.com/ http://www.roadsend.com/

Just to follow up on the suggestion to use MySQL encode and decode functions, the manual is vague on just how these work: 为了跟进使用MySQL编码和解码功能的建议,手册对这些工作方式含糊不清

The strength of the encryption is based on how good the random generator is. 加密的强度取决于随机生成器的好坏程度。 It should suffice for short strings. 它应该足够短串。

But what I'd suggest is that you can instead use the built-in MySQL 5.0 AES functions ; 但我建议你可以使用内置的MySQL 5.0 AES函数 ; AES_ENCRYPT() and AES_DECRYPT() AES_ENCRYPT()AES_DECRYPT()

SELECT AES_ENCRYPT('secret squirrel', '12345678') AS encoded

=> ØA;J×ÍfOU»] É8

SELECT AES_DECRYPT('ØA;J×ÍfOU»] É8', '12345678') AS decoded

=> secret squirrel

These use 128-bit AES which should be strong enough for most purposes. 这些使用128位AES,对于大多数用途来说应该足够强大。 As others commented, using a salt value and a key with a high entropy is a good practice. 正如其他人评论的那样,使用盐值和具有高熵的密钥是一种很好的做法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM