如何保护API密钥和第三方站点凭据(LAMP)?

时间:2022-11-24 23:15:00

I'm creating a site which will make use of ID's, Passwords, and API Keys to other 3rd party sites - for the server to access information accordingly. For the purpose of this conversation, let's assume it is for a payment gateway - meaning exposure of this information that is stored in the DB could mean a malicious user could withdraw cash from the account whose credentials were leaked.

我正在创建一个网站,该网站将使用ID,密码和API密钥到其他第三方网站 - 以便服务器相应地访问信息。出于此对话的目的,我们假设它是针对支付网关的 - 意味着存储在数据库中的此信息的暴露可能意味着恶意用户可以从其凭据泄露的帐户中提取现金。

Unfortunately this isn't like a password / hashing situation, because the user does not input the credentials every time - they input it once and it is then saved on the server for future use by the application.

不幸的是,这不像密码/散列情况,因为用户每次都不输入凭证 - 他们输入一次,然后将其保存在服务器上供应用程序以后使用。

The only reasonable method that I can come up with (this will be a MySQL/PHP application), is to encrypt the credentials via a hardcoded "password" in the PHP application. The only benefit here is that if the malicious user/hacker gains access to the database, but not the PHP code, they still have nothing. That said, this seems pointless to me because I think we can reasonably assume that a hacker will get everything if they get one or the other - right?

我能想出的唯一合理的方法(这将是一个MySQL / PHP应用程序),是通过PHP应用程序中的硬编码“密码”加密凭证。这里唯一的好处是,如果恶意用户/黑客获得对数据库的访问权限,而不是PHP代码,他们仍然没有任何东西。也就是说,这对我来说似乎毫无意义,因为我认为我们可以合理地假设一个黑客会得到一切,如果他们得到一个 - 对吗?

If the community decides upon some good solutions, it would be nice to gather other sources to examples/tutorials/more in depth information so that this can be implemented in the future for everyone.

如果社区决定一些好的解决方案,那么将其他来源收集到示例/教程/更深入的信息中会很好,以便将来可以为每个人实施。

I was surprised I did not see this question with any good answers on stack already. I did find this one, but in my case this doesn't really apply: How should I ethically approach user password storage for later plaintext retrieval?

我很惊讶我没有在堆栈上看到任何好的答案这个问题。我确实找到了这个,但在我的情况下,这并不适用:我应该如何道德地接近用户密码存储以便以后的明文检索?

Thanks all.

谢谢大家。

5 个解决方案

#1


8  

Based on what I can see in the question, answers, and comments; I would suggest taking advantage of OpenSSL. This is assuming that your site needs access to this information periodically (meaning it can be scheduled). As you stated:

基于我在问题,答案和评论中可以看到的内容;我建议利用OpenSSL。这假设您的站点需要定期访问此信息(这意味着可以安排)。如你所说:

The server would need this information to send payments for all sorts of situations. It does not require the "owner" of said keys to log in, in fact the owner might never care to see them ever again once they provide them the first time.

服务器需要此信息才能发送各种情况的付款。它不需要所述密钥的“所有者”登录,事实上,所有者可能永远不会在第一次提供它们时再次看到它们。

It is from this comment, and the assumption that accessing the data you want to store can be put within a cron job. It is further assumed that you have SSL (https) on your server as you will be dealing with confidential user information, and have the OpenSSL and mcrypt modules available.. Also, what follows will be rather generic as to 'how' it can be achieved, but not really the details of doing it per your situation. It should also be noted that this 'how-to' is general, and you should do more research before implementing it. That being said, let's get started.

它来自此注释,并且假设访问要存储的数据可以放在cron作业中。进一步假设您的服务器上有SSL(https),因为您将处理机密的用户信息,并且可以使用OpenSSL和mcrypt模块。此外,以下内容对于“如何”可能是相当通用的。实现了,但不是真的根据你的情况做这件事的细节。还应该注意的是,这个“操作方法”是通用的,你应该在实施之前做更多的研究。话虽这么说,让我们开始吧。

First, let's talk about what OpenSSL provides. OpenSSL gives us a Public-Key Cryptography: the ability to encrypt data using a public key (which, if compromised, won't compromise the security of the data encrypted with it.) Secondly, it provides a way to access that information with a 'Private Key. As we don't care about creating a certificate (we only need encryption keys), those may be obtained with a simple function (which you'll only use once.):

首先,我们来谈谈OpenSSL提供的内容。 OpenSSL为我们提供了一个公钥加密:使用公钥加密数据的能力(如果受到损害,不会损害用它加密的数据的安全性。)其次,它提供了一种方法来访问该信息。 '私钥。因为我们不关心创建证书(我们只需要加密密钥),所以可以通过一个简单的函数(您只使用一次)获得这些证书:

function makeKeyPair()
{
    //Define variables that will be used, set to ''
    $private = '';
    $public = '';
    //Generate the resource for the keys
    $resource = openssl_pkey_new();

    //get the private key
    openssl_pkey_export($resource, $private);

    //get the public key
    $public = openssl_pkey_get_details($resource);
    $public = $public["key"];
    $ret = array('privateKey' => $private, 'publicKey' => $public);
    return $ret;
}

Now, you have a Public and Private key. Guard the private key, keep it off your server, and keep it out of the database. Store it on another server, a computer that can run cron jobs, etc. Just nowhere near the public eye unless you can require an admin to be present every time you require a payment to be processed and encrypt the private key with AES encryption or something similar. The public key, however, will be hard-coded in to your application, and will be used every time a user enters their information to be stored.

现在,您有一个公钥和私钥。保护私钥,将其从服务器上移除,并将其保留在数据库之外。将它存储在另一台服务器,一台可以运行cron作业的计算机上等等。除非您每次需要付款处理并使用AES加密或其他东西加密私钥时都要求管理员在场类似。但是,公钥将被硬编码到您的应用程序中,并且每次用户输入要存储的信息时都会使用该公钥。

Next, you need to determine how you plan to verify the decrypted data (so you don't start posting to payment APIs with invalid requests.) I am going to assume there are multiple fields that need to be stored, and as we only want to encrypt once, it will be in a PHP array that can be serialize'd. Depending on how much data needs to be stored, we'll either be able to encrypt it directly, or generate a password to encrypt with the public key, and use that random password to encrypt that data itself. I am going to go this route in the explanation. To go this route, we will use AES encryption, and need to have an encrypt and decrypt function handy - as well as a way to randomly generate a decent one-time pad for the data. I'll provide the password generator that I use, though I ported it from code I wrote a while back, it will serve the purpose, or you can write a better one. ^^

接下来,您需要确定计划如何验证解密数据(因此您不会开始使用无效请求发布到支付API。)我将假设有多个字段需要存储,因为我们只想要加密一次,它将在一个可以序列化的PHP数组中。根据需要存储的数据量,我们要么能够直接对其进行加密,要么生成密码以使用公钥进行加密,并使用该随机密码来加密该数据本身。我将在解释中走这条路。要走这条路线,我们将使用AES加密,并且需要一个方便的加密和解密功能 - 以及为数据随机生成一个合适的一次性填充的方法。我将提供我使用的密码生成器,虽然我从我稍后写的代码中移植它,它将用于此目的,或者您可以编写更好的密码生成器。 ^^

public function generatePassword() {
    //create a random password here
    $chars = array( 'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'h', 'H', 'i', 'I', 'j', 'J',  'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N', 'o', 'O', 'p', 'P', 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T',  'u', 'U', 'v', 'V', 'w', 'W', 'x', 'X', 'y', 'Y', 'z', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '?', '<', '>', '.', ',', ';', '-', '@', '!', '#', '$', '%', '^', '&', '*', '(', ')');

    $max_chars = count($chars) - 1;
    srand( (double) microtime()*1000000);

    $rand_str = '';
    for($i = 0; $i < 30; $i++)
    {
            $rand_str .= $chars[rand(0, $max_chars)];
    }
    return $rand_str;

}

This particular function will generate 30 digits, which provides decent entropy - but you can modify it for your needs. Next, the function to do AES encryption:

这个特殊的功能将生成30个数字,提供了不错的熵 - 但您可以根据需要进行修改。接下来,进行AES加密的功能:

/**
 * Encrypt AES
 *
 * Will Encrypt data with a password in AES compliant encryption.  It
 * adds built in verification of the data so that the {@link this::decryptAES}
 * can verify that the decrypted data is correct.
 *
 * @param String $data This can either be string or binary input from a file
 * @param String $pass The Password to use while encrypting the data
 * @return String The encrypted data in concatenated base64 form.
 */
public function encryptAES($data, $pass) {
    //First, let's change the pass into a 256bit key value so we get 256bit encryption
    $pass = hash('SHA256', $pass, true);
    //Randomness is good since the Initialization Vector(IV) will need it
    srand();
    //Create the IV (CBC mode is the most secure we get)
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
    //Create a base64 version of the IV and remove the padding
    $base64IV = rtrim(base64_encode($iv), '=');
    //Create our integrity check hash
    $dataHash = md5($data);
    //Encrypt the data with AES 128 bit (include the hash at the end of the data for the integrity check later)
    $rawEnc = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $pass, $data . $dataHash, MCRYPT_MODE_CBC, $iv);
    //Transfer the encrypted data from binary form using base64
    $baseEnc = base64_encode($rawEnc);
    //attach the IV to the front of the encrypted data (concatenated IV)
    $ret = $base64IV . $baseEnc;
    return $ret;
}

(I wrote these function originally to be part of a class, and suggest you implement them in to a class of your own.) Also, use of this function is fine with a one-time pad that is created, however, if used with a user-specific password for a different application, you definitely need some salt in there to add to the password. Next, to decrypt and verify the decrypted data is correct:

(我最初将这些函数编写为类的一部分,并建议您将它们实现到您自己的类中。)此外,使用此函数可以使用创建的一次性填充,但是,如果与之一起使用对于不同的应用程序的用户专用密码,你肯定需要一些盐来添加密码。接下来,解密并验证解密数据是否正确:

/**
 * Decrypt AES
 *
 * Decrypts data previously encrypted WITH THIS CLASS, and checks the
 * integrity of that data before returning it to the programmer.
 *
 * @param String $data The encrypted data we will work with
 * @param String $pass The password used for decryption
 * @return String|Boolean False if the integrity check doesn't pass, or the raw decrypted data.
 */
public function decryptAES($data, $pass){
    //We used a 256bit key to encrypt, recreate the key now
    $pass = hash('SHA256', $this->salt . $pass, true);
    //We should have a concatenated data, IV in the front - get it now
    //NOTE the IV base64 should ALWAYS be 22 characters in length.
    $base64IV = substr($data, 0, 22) .'=='; //add padding in case PHP changes at some point to require it
    //change the IV back to binary form
    $iv = base64_decode($base64IV);
    //Remove the IV from the data
    $data = substr($data, 22);
    //now convert the data back to binary form
    $data = base64_decode($data);
    //Now we can decrypt the data
    $decData = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $pass, $data, MCRYPT_MODE_CBC, $iv);
    //Now we trim off the padding at the end that php added
    $decData = rtrim($decData, "\0");
    //Get the md5 hash we stored at the end
    $dataHash = substr($decData, -32);
    //Remove the hash from the data
    $decData = substr($decData, 0, -32);
    //Integrity check, return false if it doesn't pass
    if($dataHash != md5($decData)) {
        return false;
    } else {
        //Passed the integrity check, give use their data
        return $decData;
    }
}

Look at both of the functions, read the comments, etc. Figure out what they do and how they work so you don't implement them incorrectly. Now, to encrypting the user-data. We'll encrypt it with the public key, and the following functions assume that every function so far (and to come) is in the same class. I'll provide both the OpenSSL encrypt/decrypt functions at once as we'll need the second later.

查看这两个函数,阅读注释等。找出它们的作用以及它们的工作方式,这样就不会错误地实现它们。现在,加密用户数据。我们将使用公钥对其进行加密,并且以下函数假定到目前为止(和将来)的每个函数都在同一个类中。我将立即提供OpenSSL加密/解密功能,因为我们稍后需要第二个。

/**
 * Public Encryption
 *
 * Will encrypt data based on the public key
 *
 * @param String $data The data to encrypt
 * @param String $publicKey The public key to use
 * @return String The Encrypted data in base64 coding
 */
public function publicEncrypt($data, $publicKey) {
    //Set up the variable to get the encrypted data
    $encData = '';
    openssl_public_encrypt($data, $encData, $publicKey);
    //base64 code the encrypted data
    $encData = base64_encode($encData);
    //return it
    return $encData;
}

/**
 * Private Decryption
 *
 * Decrypt data that was encrypted with the assigned private
 * key's public key match. (You can't decrypt something with
 * a private key if it doesn't match the public key used.)
 *
 * @param String $data The data to decrypt (in base64 format)
 * @param String $privateKey The private key to decrypt with.
 * @return String The raw decoded data
 */
public function privateDecrypt($data, $privateKey) {
    //Set up the variable to catch the decoded date
    $decData = '';
    //Remove the base64 encoding on the inputted data
    $data = base64_decode($data);
    //decrypt it
    openssl_private_decrypt($data, $decData, $privateKey);
    //return the decrypted data
    return $decData;
}

The $data in these is always going to be the one-time pad, not the user information. Next, the functions to combine both the Public Key Encryption and AES of the one-time pad for encryption and decryption.

这些中的$ data始终是一次性填充,而不是用户信息。接下来,将公钥加密和一次性密码的AES结合起来进行加密和解密的功能。

/**
 * Secure Send
 *
 * OpenSSL and 'public-key' schemes are good for sending
 * encrypted messages to someone that can then use their
 * private key to decrypt it.  However, for large amounts
 * of data, this method is incredibly slow (and limited).
 * This function will take the public key to encrypt the data
 * to, and using that key will encrypt a one-time-use randomly
 * generated password.  That one-time password will be
 * used to encrypt the data that is provided.  So the data
 * will be encrypted with a one-time password that only
 * the owner of the private key will be able to uncover.
 * This method will return a base64encoded serialized array
 * so that it can easily be stored, and all parts are there
 * without modification for the receive function
 *
 * @param String $data The data to encrypt
 * @param String $publicKey The public key to use
 * @return String serialized array of 'password' and 'data'
 */
public function secureSend($data, $publicKey)
{
    //First, we'll create a 30digit random password
    $pass = $this->generatePassword();
    //Now, we will encrypt in AES the data
    $encData = $this->encryptAES($data, $pass);
    //Now we will encrypt the password with the public key
    $pass = $this->publicEncrypt($pass, $publicKey);
    //set up the return array
    $ret = array('password' => $pass, 'data' => $encData);
    //serialize the array and then base64 encode it
    $ret = serialize($ret);
    $ret = base64_encode($ret);
    //send it on its way
    return $ret;
}

/**
 * Secure Receive
 *
 * This is the complement of {@link this::secureSend}.
 * Pass the data that was returned from secureSend, and it
 * will dismantle it, and then decrypt it based on the
 * private key provided.
 *
 * @param String $data the base64 serialized array
 * @param String $privateKey The private key to use
 * @return String the decoded data.
 */
public function secureReceive($data, $privateKey) {
    //Let's decode the base64 data
    $data = base64_decode($data);
    //Now let's put it into array format
    $data = unserialize($data);
    //assign variables for the different parts
    $pass = $data['password'];
    $data = $data['data'];
    //Now we'll get the AES password by decrypting via OpenSSL
    $pass = $this->privateDecrypt($pass, $privateKey);
    //and now decrypt the data with the password we found
    $data = $this->decryptAES($data, $pass);
    //return the data
    return $data;
}

I left the comments intact to help understanding of these functions. Now is where we get down to the fun part, actually working with the users data. The $data in the send method is the user-data in a serialized array. Remember for the send method that the $publicKey is hard-coded, you can store as a variable in your class and access it that way for less variables to pass to it, or have it inputted from elsewhere to send to the method every time. Example usage to encrypt the data:

我保留了完整的评论,以帮助理解这些功能。现在是我们开始讨论有趣部分的地方,实际上是在处理用户数据。 send方法中的$ data是序列化数组中的用户数据。请记住,对于$ publicKey是硬编码的send方法,您可以将其作为变量存储在类中,并以这种方式访问​​它,以便将较少的变量传递给它,或者让它从其他地方输入以便每次都发送到该方法。加密数据的示例用法:

$myCrypt = new encryptClass();
$userData = array(
    'id' => $_POST['id'],
    'password' => $_POST['pass'],
    'api' => $_POST['api_key']
);
$publicKey = "the public key from earlier";
$encData = $myCrypt->secureSend(serialize($userData), $publicKey));
//Now store the $encData in the DB with a way to associate with the user
//it is base64 encoded, so it is safe for DB input.

Now, that's the easy part, the next part is being able to use that data. For that, you'll need a page on your server that accepts $_POST['privKey'] and will then loop through the users, etc in the fashion that is needed for your site, grabbing the $encData. Sample usage to decrypt from this:

现在,这是最简单的部分,下一部分是能够使用该数据。为此,您需要在服务器上接受$ _POST ['privKey']的页面,然后以您网站所需的方式循环访问用户等,获取$ encData。用于解密的示例用法:

$myCrypt = new encryptClass();
$encData = "pulled from DB";
$privKey = $_POST['privKey'];
$data = unserialize($myCrypt->secureReceive($encData, $privKey));
//$data will now contain the original array of data, or false if
//it failed to decrypt it.  Now do what you need with it.

Next, the specific theory of use to access that secure page with the private key. On a separate server, you'll have a cron job that runs a php script specifically not in public_html containing the private key, then use curl to post the private key to your page that is looking for it. (Make sure you are calling an address that begins with https)

接下来,使用特定的理论来访问具有私钥的安全页面。在一个单独的服务器上,你将有一个运行php脚本的cron作业,特别是在包含私钥的public_html中,然后使用curl将私钥发布到正在查找它的页面。 (确保您拨打的是以https开头的地址)

I hope that helps answer how it is possible to store the user information securely within your application that won't be compromised by accessing either your code or your database.

我希望这有助于回答如何在您的应用程序中安全地存储用户信息,这些信息不会因访问您的代码或数据库而受到损害。

#2


2  

Let me see if I can summarize the problem - and then my answer to what I understand the problem.

让我看看我是否可以总结问题 - 然后我回答我理解的问题。

You would like to have users login to your application, and then store 3rd party credentials. (It doesn't matter what those credentials are...) For security, you'd like there not to be an easy way to decrypt those credentials in the case of a hacker gaining access to the database.

您希望让用户登录您的应用程序,然后存储第三方凭据。 (这些凭据是什么并不重要......)为了安全起见,您希望在黑客获得对数据库的访问权限时,不能轻易解密这些凭据。

Here is what I suggest.

这是我的建议。

  1. Create an authentication system for the user to log in to your application. The user MUST login each time they visit the site. When storing access to all of these other credentials, a "remember me" is just a horrible idea. Authentication is created by combining and hashing username, password, and a salt. This way, none of that information is stored in the db.

    为用户创建一个身份验证系统,以登录您的应用程序。用户每次访问该站点时都必须登录。当存储对所有这些其他凭据的访问时,“记住我”只是一个可怕的想法。通过组合和散列用户名,密码和salt来创建身份验证。这样,这些信息都不会存储在数据库中。

  2. A hashed version of the username / password combination is stored in the session. This becomes the MASTER KEY.

    用户名/密码组合的散列版本存储在会话中。这成为MASTER KEY。

  3. 3rd party information is entered. This information is encrypted using the MASTER KEY hash.

    输入第三方信息。使用MASTER KEY哈希加密此信息。

So this means...

所以这意味着......

If a user doesn't know their password, they are out of luck. However, it would be a very difficult situation for a hacker to get the information. They would need to understand the hashing of the username, password, salt, to break authentication, then have that hashed version of hte username/password for the master key, and then use that to decyrpt the data.

如果用户不知道他们的密码,他们就不走运了。但是,黑客获取信息将是一个非常困难的情况。他们需要了解用户名,密码,盐的哈希,以破坏身份验证,然后为主密钥使用哈希用户名/密码的哈希版本,然后使用它来解密数据。

It is possible to still be hacked, but very hard - unprobable. I would also say this gives you relative deniability because, according to this method, you never know the information on the server, as it is encrypted before it is stored. This method is similar to how I assume services like OnePassword work.

它仍然可能被黑客入侵,但非常难 - 不可能。我还会说这会给你相对的否定性,因为根据这种方法,你永远不会知道服务器上的信息,因为它在存储之前是加密的。这种方法类似于我假设像OnePassword这样的服务。

#3


2  

There are several possible solutions if you think out of the box... and can act out of the box, which isn't necessarily your case, but I'm going to suggest them anyways.

如果您开箱即用,有几种可能的解决方案......并且可以开箱即用,这不一定是您的情况,但无论如何我都会建议它们。

  1. Obtain accounts with limited permissions from the 3rd party site. In your payment gateway example, an account that allows you to authorize and settle payments, but not to call the TransferToBankAccount($accountNumber) API.

    从第三方网站获取具有有限权限的帐户。在您的支付网关示例中,该帐户允许您授权和结算付款,但不能调用TransferToBankAccount($ accountNumber)API。

    • Similarly, ask the provider to put in restrictions. $accountNumber has to be one of several you've provided or maybe just has to be in the same country as you're located in*.
    • 同样,要求提供商加入限制。 $ accountNumber必须是您提供的几个中的一个,或者只是必须与您位于*中的同一个国家/地区。
  2. Some secure systems rely on a hardware token to provide authentication. (I'm mostly thinking of key-creation and signing dongles.) I'm not sure exactly how this would work in your situation. Assume you've got a dongle that you request the authentication from and it'll only reply under certain circumstances. This is difficult if all it can do is to give (or not give) a username / password. (Vs say, signing a request, where it can examine the request parameters). You could possibly do this with a SSL client certificate, where the request to the 3rd party requires the username / pass / and client signature -- if your 3rd party would accept such a thing.

    某些安全系统依赖硬件令牌来提供身份验证。 (我主要考虑密钥创建和签名加密狗。)我不确定这在你的情况下究竟是如何工作的。假设您有一个加密狗,您要求进行身份验证,它只会在某些情况下回复。如果所能做的只是给(或不给)用户名/密码,这很难。 (比如说,签署一个请求,它可以检查请求参数)。您可以使用SSL客户端证书执行此操作,其中对第三方的请求需要用户名/密码/和客户端签名 - 如果您的第三方接受此类事件。

  3. A combination of #1 and #2. Set up another server to act as a go-between. This server would implement basic business logic that I suggested your 3rd party could do in #1. It exposes an API and checks to make sure that the request is "valid" (payments can be settled, but only outgoing transfers to your account #, etc) before grabbing the auth details and making the request directly. The API can include SetAuthDetails, but not GetAuthDetails. The benefit here is that it's one more thing for the attacker to compromise. And, the simpler the server the easier it is to harden. (No need to run SMTP, FTP, and whatever potentially buggy PHP stack your main server has.... just a few PHP scripts, port 443, SSH, and a, e.g., sqlite instance. Keeping the HTTPD and PHP up to date should be easier because there's less concern about compatibility issues.)

    #1和#2的组合。设置另一台服务器作为中间人。该服务器将实现我建议您的第三方可以在#1中执行的基本业务逻辑。它会公开API并检查以确保请求是“有效”(付款可以结算,但只能传输到您的帐户#等,然后才能获取身份验证详细信息并直接发出请求)。 API可以包含SetAuthDetails,但不包括GetAuthDetails。这样做的好处是攻击者可以妥协的另一件事。而且,服务器越简单就越容易硬化。 (无需运行SMTP,FTP,以及您的主服务器所具有的任何潜在错误的PHP堆栈....只需几个PHP脚本,端口443,SSH和一个例如sqlite实例。保持HTTPD和PHP最新应该更容易,因为对兼容性问题的关注较少。)

  4. Assume you will get compromised and monitor / audit for the potential effects. Have another server somewhere that (yes) has the auth details to log in and check the auth logs (or, ideally, read-only permission). Have it check every minute and check for unauthorized logins and / or transactions and do something drastic (maybe change the password to something random and page you).

    假设您将受到损害并监控/审核潜在影响。在某个地方安装另一台服务器(是)具有登录的auth详细信息并检查auth日志(或理想情况下,只读权限)。让它检查每一分钟并检查未经授权的登录和/或交易,并做一些激烈的事情(可能会将密码更改为随机的内容并为您提供页面)。

*Whether we're actually talking about a payment gateway or not, any 3rd party that you're this concerned about being hacked over should also be concerned about their own security, including if you (or other clients) get hacked. They're also liable to one extent or another, so they should be willing to put in safeguards.

*无论我们是否真的在谈论支付网关,你担心被黑客入侵的任何第三方也应该关注自己的安全性,包括你(或其他客户)被黑客入侵。他们也在某种程度上承担责任,因此他们应该愿意提供保障。

#4


0  

If you use a random salt based on X criteria that you can predict but that a hacker couldn't then depending on how you write the code it still may not be apparent what is what even if the hacker gains access to everything.

如果您使用基于X标准的随机盐,您可以预测,但黑客无法取决于您编写代码的方式,即使黑客获得对所有内容的访问权限,仍然可能不明显是什么。

For example, you use the current time and date plus the users IP address as a salt. You then store those values along with the hash in he database. You obfuscate the function used to create the hash and it might not be so obvious what the salt was. Of course any determined hacker can break that eventually but it buys you time and some additional level of protection.

例如,您使用当前时间和日期加上用户IP地址作为salt。然后,将这些值与哈希值一起存储在数据库中。您混淆了用于创建哈希的函数,并且盐可能不那么明显。当然,任何坚定的黑客最终都可以打破这种局面,但它会为你带来时间和一些额外的保护。

#5


0  

Users are not all very tech savvy but a user, asked to provide credentials for a third party's site, should run away from your site as quick as he can. This is simply a bad idea. The question about storing plaintext passwords definitely applies here, too. Don't do it.

用户并非都非常精通技术,但要求为第三方网站提供凭据的用户应尽快离开您的网站。这简直是​​一个坏主意。关于存储明文密码的问题也适用于此。不要这样做。

You are not providing much context about the third parties in question nor about your relation with them. But you should talk with them about if they are willing to make some changes to support your use case. Them implementing oauth would be a good solution.

您没有提供有关第三方的大量背景信息,也没有提供您与他们的关系。但是,您应该与他们讨论是否愿意进行一些更改以支持您的用例。他们实施oauth将是一个很好的解决方案。

If you want to look around for alternatives, look up federated identity

如果您想环顾四周寻找替代方案,请查看联合身份

#1


8  

Based on what I can see in the question, answers, and comments; I would suggest taking advantage of OpenSSL. This is assuming that your site needs access to this information periodically (meaning it can be scheduled). As you stated:

基于我在问题,答案和评论中可以看到的内容;我建议利用OpenSSL。这假设您的站点需要定期访问此信息(这意味着可以安排)。如你所说:

The server would need this information to send payments for all sorts of situations. It does not require the "owner" of said keys to log in, in fact the owner might never care to see them ever again once they provide them the first time.

服务器需要此信息才能发送各种情况的付款。它不需要所述密钥的“所有者”登录,事实上,所有者可能永远不会在第一次提供它们时再次看到它们。

It is from this comment, and the assumption that accessing the data you want to store can be put within a cron job. It is further assumed that you have SSL (https) on your server as you will be dealing with confidential user information, and have the OpenSSL and mcrypt modules available.. Also, what follows will be rather generic as to 'how' it can be achieved, but not really the details of doing it per your situation. It should also be noted that this 'how-to' is general, and you should do more research before implementing it. That being said, let's get started.

它来自此注释,并且假设访问要存储的数据可以放在cron作业中。进一步假设您的服务器上有SSL(https),因为您将处理机密的用户信息,并且可以使用OpenSSL和mcrypt模块。此外,以下内容对于“如何”可能是相当通用的。实现了,但不是真的根据你的情况做这件事的细节。还应该注意的是,这个“操作方法”是通用的,你应该在实施之前做更多的研究。话虽这么说,让我们开始吧。

First, let's talk about what OpenSSL provides. OpenSSL gives us a Public-Key Cryptography: the ability to encrypt data using a public key (which, if compromised, won't compromise the security of the data encrypted with it.) Secondly, it provides a way to access that information with a 'Private Key. As we don't care about creating a certificate (we only need encryption keys), those may be obtained with a simple function (which you'll only use once.):

首先,我们来谈谈OpenSSL提供的内容。 OpenSSL为我们提供了一个公钥加密:使用公钥加密数据的能力(如果受到损害,不会损害用它加密的数据的安全性。)其次,它提供了一种方法来访问该信息。 '私钥。因为我们不关心创建证书(我们只需要加密密钥),所以可以通过一个简单的函数(您只使用一次)获得这些证书:

function makeKeyPair()
{
    //Define variables that will be used, set to ''
    $private = '';
    $public = '';
    //Generate the resource for the keys
    $resource = openssl_pkey_new();

    //get the private key
    openssl_pkey_export($resource, $private);

    //get the public key
    $public = openssl_pkey_get_details($resource);
    $public = $public["key"];
    $ret = array('privateKey' => $private, 'publicKey' => $public);
    return $ret;
}

Now, you have a Public and Private key. Guard the private key, keep it off your server, and keep it out of the database. Store it on another server, a computer that can run cron jobs, etc. Just nowhere near the public eye unless you can require an admin to be present every time you require a payment to be processed and encrypt the private key with AES encryption or something similar. The public key, however, will be hard-coded in to your application, and will be used every time a user enters their information to be stored.

现在,您有一个公钥和私钥。保护私钥,将其从服务器上移除,并将其保留在数据库之外。将它存储在另一台服务器,一台可以运行cron作业的计算机上等等。除非您每次需要付款处理并使用AES加密或其他东西加密私钥时都要求管理员在场类似。但是,公钥将被硬编码到您的应用程序中,并且每次用户输入要存储的信息时都会使用该公钥。

Next, you need to determine how you plan to verify the decrypted data (so you don't start posting to payment APIs with invalid requests.) I am going to assume there are multiple fields that need to be stored, and as we only want to encrypt once, it will be in a PHP array that can be serialize'd. Depending on how much data needs to be stored, we'll either be able to encrypt it directly, or generate a password to encrypt with the public key, and use that random password to encrypt that data itself. I am going to go this route in the explanation. To go this route, we will use AES encryption, and need to have an encrypt and decrypt function handy - as well as a way to randomly generate a decent one-time pad for the data. I'll provide the password generator that I use, though I ported it from code I wrote a while back, it will serve the purpose, or you can write a better one. ^^

接下来,您需要确定计划如何验证解密数据(因此您不会开始使用无效请求发布到支付API。)我将假设有多个字段需要存储,因为我们只想要加密一次,它将在一个可以序列化的PHP数组中。根据需要存储的数据量,我们要么能够直接对其进行加密,要么生成密码以使用公钥进行加密,并使用该随机密码来加密该数据本身。我将在解释中走这条路。要走这条路线,我们将使用AES加密,并且需要一个方便的加密和解密功能 - 以及为数据随机生成一个合适的一次性填充的方法。我将提供我使用的密码生成器,虽然我从我稍后写的代码中移植它,它将用于此目的,或者您可以编写更好的密码生成器。 ^^

public function generatePassword() {
    //create a random password here
    $chars = array( 'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'h', 'H', 'i', 'I', 'j', 'J',  'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N', 'o', 'O', 'p', 'P', 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T',  'u', 'U', 'v', 'V', 'w', 'W', 'x', 'X', 'y', 'Y', 'z', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '?', '<', '>', '.', ',', ';', '-', '@', '!', '#', '$', '%', '^', '&', '*', '(', ')');

    $max_chars = count($chars) - 1;
    srand( (double) microtime()*1000000);

    $rand_str = '';
    for($i = 0; $i < 30; $i++)
    {
            $rand_str .= $chars[rand(0, $max_chars)];
    }
    return $rand_str;

}

This particular function will generate 30 digits, which provides decent entropy - but you can modify it for your needs. Next, the function to do AES encryption:

这个特殊的功能将生成30个数字,提供了不错的熵 - 但您可以根据需要进行修改。接下来,进行AES加密的功能:

/**
 * Encrypt AES
 *
 * Will Encrypt data with a password in AES compliant encryption.  It
 * adds built in verification of the data so that the {@link this::decryptAES}
 * can verify that the decrypted data is correct.
 *
 * @param String $data This can either be string or binary input from a file
 * @param String $pass The Password to use while encrypting the data
 * @return String The encrypted data in concatenated base64 form.
 */
public function encryptAES($data, $pass) {
    //First, let's change the pass into a 256bit key value so we get 256bit encryption
    $pass = hash('SHA256', $pass, true);
    //Randomness is good since the Initialization Vector(IV) will need it
    srand();
    //Create the IV (CBC mode is the most secure we get)
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
    //Create a base64 version of the IV and remove the padding
    $base64IV = rtrim(base64_encode($iv), '=');
    //Create our integrity check hash
    $dataHash = md5($data);
    //Encrypt the data with AES 128 bit (include the hash at the end of the data for the integrity check later)
    $rawEnc = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $pass, $data . $dataHash, MCRYPT_MODE_CBC, $iv);
    //Transfer the encrypted data from binary form using base64
    $baseEnc = base64_encode($rawEnc);
    //attach the IV to the front of the encrypted data (concatenated IV)
    $ret = $base64IV . $baseEnc;
    return $ret;
}

(I wrote these function originally to be part of a class, and suggest you implement them in to a class of your own.) Also, use of this function is fine with a one-time pad that is created, however, if used with a user-specific password for a different application, you definitely need some salt in there to add to the password. Next, to decrypt and verify the decrypted data is correct:

(我最初将这些函数编写为类的一部分,并建议您将它们实现到您自己的类中。)此外,使用此函数可以使用创建的一次性填充,但是,如果与之一起使用对于不同的应用程序的用户专用密码,你肯定需要一些盐来添加密码。接下来,解密并验证解密数据是否正确:

/**
 * Decrypt AES
 *
 * Decrypts data previously encrypted WITH THIS CLASS, and checks the
 * integrity of that data before returning it to the programmer.
 *
 * @param String $data The encrypted data we will work with
 * @param String $pass The password used for decryption
 * @return String|Boolean False if the integrity check doesn't pass, or the raw decrypted data.
 */
public function decryptAES($data, $pass){
    //We used a 256bit key to encrypt, recreate the key now
    $pass = hash('SHA256', $this->salt . $pass, true);
    //We should have a concatenated data, IV in the front - get it now
    //NOTE the IV base64 should ALWAYS be 22 characters in length.
    $base64IV = substr($data, 0, 22) .'=='; //add padding in case PHP changes at some point to require it
    //change the IV back to binary form
    $iv = base64_decode($base64IV);
    //Remove the IV from the data
    $data = substr($data, 22);
    //now convert the data back to binary form
    $data = base64_decode($data);
    //Now we can decrypt the data
    $decData = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $pass, $data, MCRYPT_MODE_CBC, $iv);
    //Now we trim off the padding at the end that php added
    $decData = rtrim($decData, "\0");
    //Get the md5 hash we stored at the end
    $dataHash = substr($decData, -32);
    //Remove the hash from the data
    $decData = substr($decData, 0, -32);
    //Integrity check, return false if it doesn't pass
    if($dataHash != md5($decData)) {
        return false;
    } else {
        //Passed the integrity check, give use their data
        return $decData;
    }
}

Look at both of the functions, read the comments, etc. Figure out what they do and how they work so you don't implement them incorrectly. Now, to encrypting the user-data. We'll encrypt it with the public key, and the following functions assume that every function so far (and to come) is in the same class. I'll provide both the OpenSSL encrypt/decrypt functions at once as we'll need the second later.

查看这两个函数,阅读注释等。找出它们的作用以及它们的工作方式,这样就不会错误地实现它们。现在,加密用户数据。我们将使用公钥对其进行加密,并且以下函数假定到目前为止(和将来)的每个函数都在同一个类中。我将立即提供OpenSSL加密/解密功能,因为我们稍后需要第二个。

/**
 * Public Encryption
 *
 * Will encrypt data based on the public key
 *
 * @param String $data The data to encrypt
 * @param String $publicKey The public key to use
 * @return String The Encrypted data in base64 coding
 */
public function publicEncrypt($data, $publicKey) {
    //Set up the variable to get the encrypted data
    $encData = '';
    openssl_public_encrypt($data, $encData, $publicKey);
    //base64 code the encrypted data
    $encData = base64_encode($encData);
    //return it
    return $encData;
}

/**
 * Private Decryption
 *
 * Decrypt data that was encrypted with the assigned private
 * key's public key match. (You can't decrypt something with
 * a private key if it doesn't match the public key used.)
 *
 * @param String $data The data to decrypt (in base64 format)
 * @param String $privateKey The private key to decrypt with.
 * @return String The raw decoded data
 */
public function privateDecrypt($data, $privateKey) {
    //Set up the variable to catch the decoded date
    $decData = '';
    //Remove the base64 encoding on the inputted data
    $data = base64_decode($data);
    //decrypt it
    openssl_private_decrypt($data, $decData, $privateKey);
    //return the decrypted data
    return $decData;
}

The $data in these is always going to be the one-time pad, not the user information. Next, the functions to combine both the Public Key Encryption and AES of the one-time pad for encryption and decryption.

这些中的$ data始终是一次性填充,而不是用户信息。接下来,将公钥加密和一次性密码的AES结合起来进行加密和解密的功能。

/**
 * Secure Send
 *
 * OpenSSL and 'public-key' schemes are good for sending
 * encrypted messages to someone that can then use their
 * private key to decrypt it.  However, for large amounts
 * of data, this method is incredibly slow (and limited).
 * This function will take the public key to encrypt the data
 * to, and using that key will encrypt a one-time-use randomly
 * generated password.  That one-time password will be
 * used to encrypt the data that is provided.  So the data
 * will be encrypted with a one-time password that only
 * the owner of the private key will be able to uncover.
 * This method will return a base64encoded serialized array
 * so that it can easily be stored, and all parts are there
 * without modification for the receive function
 *
 * @param String $data The data to encrypt
 * @param String $publicKey The public key to use
 * @return String serialized array of 'password' and 'data'
 */
public function secureSend($data, $publicKey)
{
    //First, we'll create a 30digit random password
    $pass = $this->generatePassword();
    //Now, we will encrypt in AES the data
    $encData = $this->encryptAES($data, $pass);
    //Now we will encrypt the password with the public key
    $pass = $this->publicEncrypt($pass, $publicKey);
    //set up the return array
    $ret = array('password' => $pass, 'data' => $encData);
    //serialize the array and then base64 encode it
    $ret = serialize($ret);
    $ret = base64_encode($ret);
    //send it on its way
    return $ret;
}

/**
 * Secure Receive
 *
 * This is the complement of {@link this::secureSend}.
 * Pass the data that was returned from secureSend, and it
 * will dismantle it, and then decrypt it based on the
 * private key provided.
 *
 * @param String $data the base64 serialized array
 * @param String $privateKey The private key to use
 * @return String the decoded data.
 */
public function secureReceive($data, $privateKey) {
    //Let's decode the base64 data
    $data = base64_decode($data);
    //Now let's put it into array format
    $data = unserialize($data);
    //assign variables for the different parts
    $pass = $data['password'];
    $data = $data['data'];
    //Now we'll get the AES password by decrypting via OpenSSL
    $pass = $this->privateDecrypt($pass, $privateKey);
    //and now decrypt the data with the password we found
    $data = $this->decryptAES($data, $pass);
    //return the data
    return $data;
}

I left the comments intact to help understanding of these functions. Now is where we get down to the fun part, actually working with the users data. The $data in the send method is the user-data in a serialized array. Remember for the send method that the $publicKey is hard-coded, you can store as a variable in your class and access it that way for less variables to pass to it, or have it inputted from elsewhere to send to the method every time. Example usage to encrypt the data:

我保留了完整的评论,以帮助理解这些功能。现在是我们开始讨论有趣部分的地方,实际上是在处理用户数据。 send方法中的$ data是序列化数组中的用户数据。请记住,对于$ publicKey是硬编码的send方法,您可以将其作为变量存储在类中,并以这种方式访问​​它,以便将较少的变量传递给它,或者让它从其他地方输入以便每次都发送到该方法。加密数据的示例用法:

$myCrypt = new encryptClass();
$userData = array(
    'id' => $_POST['id'],
    'password' => $_POST['pass'],
    'api' => $_POST['api_key']
);
$publicKey = "the public key from earlier";
$encData = $myCrypt->secureSend(serialize($userData), $publicKey));
//Now store the $encData in the DB with a way to associate with the user
//it is base64 encoded, so it is safe for DB input.

Now, that's the easy part, the next part is being able to use that data. For that, you'll need a page on your server that accepts $_POST['privKey'] and will then loop through the users, etc in the fashion that is needed for your site, grabbing the $encData. Sample usage to decrypt from this:

现在,这是最简单的部分,下一部分是能够使用该数据。为此,您需要在服务器上接受$ _POST ['privKey']的页面,然后以您网站所需的方式循环访问用户等,获取$ encData。用于解密的示例用法:

$myCrypt = new encryptClass();
$encData = "pulled from DB";
$privKey = $_POST['privKey'];
$data = unserialize($myCrypt->secureReceive($encData, $privKey));
//$data will now contain the original array of data, or false if
//it failed to decrypt it.  Now do what you need with it.

Next, the specific theory of use to access that secure page with the private key. On a separate server, you'll have a cron job that runs a php script specifically not in public_html containing the private key, then use curl to post the private key to your page that is looking for it. (Make sure you are calling an address that begins with https)

接下来,使用特定的理论来访问具有私钥的安全页面。在一个单独的服务器上,你将有一个运行php脚本的cron作业,特别是在包含私钥的public_html中,然后使用curl将私钥发布到正在查找它的页面。 (确保您拨打的是以https开头的地址)

I hope that helps answer how it is possible to store the user information securely within your application that won't be compromised by accessing either your code or your database.

我希望这有助于回答如何在您的应用程序中安全地存储用户信息,这些信息不会因访问您的代码或数据库而受到损害。

#2


2  

Let me see if I can summarize the problem - and then my answer to what I understand the problem.

让我看看我是否可以总结问题 - 然后我回答我理解的问题。

You would like to have users login to your application, and then store 3rd party credentials. (It doesn't matter what those credentials are...) For security, you'd like there not to be an easy way to decrypt those credentials in the case of a hacker gaining access to the database.

您希望让用户登录您的应用程序,然后存储第三方凭据。 (这些凭据是什么并不重要......)为了安全起见,您希望在黑客获得对数据库的访问权限时,不能轻易解密这些凭据。

Here is what I suggest.

这是我的建议。

  1. Create an authentication system for the user to log in to your application. The user MUST login each time they visit the site. When storing access to all of these other credentials, a "remember me" is just a horrible idea. Authentication is created by combining and hashing username, password, and a salt. This way, none of that information is stored in the db.

    为用户创建一个身份验证系统,以登录您的应用程序。用户每次访问该站点时都必须登录。当存储对所有这些其他凭据的访问时,“记住我”只是一个可怕的想法。通过组合和散列用户名,密码和salt来创建身份验证。这样,这些信息都不会存储在数据库中。

  2. A hashed version of the username / password combination is stored in the session. This becomes the MASTER KEY.

    用户名/密码组合的散列版本存储在会话中。这成为MASTER KEY。

  3. 3rd party information is entered. This information is encrypted using the MASTER KEY hash.

    输入第三方信息。使用MASTER KEY哈希加密此信息。

So this means...

所以这意味着......

If a user doesn't know their password, they are out of luck. However, it would be a very difficult situation for a hacker to get the information. They would need to understand the hashing of the username, password, salt, to break authentication, then have that hashed version of hte username/password for the master key, and then use that to decyrpt the data.

如果用户不知道他们的密码,他们就不走运了。但是,黑客获取信息将是一个非常困难的情况。他们需要了解用户名,密码,盐的哈希,以破坏身份验证,然后为主密钥使用哈希用户名/密码的哈希版本,然后使用它来解密数据。

It is possible to still be hacked, but very hard - unprobable. I would also say this gives you relative deniability because, according to this method, you never know the information on the server, as it is encrypted before it is stored. This method is similar to how I assume services like OnePassword work.

它仍然可能被黑客入侵,但非常难 - 不可能。我还会说这会给你相对的否定性,因为根据这种方法,你永远不会知道服务器上的信息,因为它在存储之前是加密的。这种方法类似于我假设像OnePassword这样的服务。

#3


2  

There are several possible solutions if you think out of the box... and can act out of the box, which isn't necessarily your case, but I'm going to suggest them anyways.

如果您开箱即用,有几种可能的解决方案......并且可以开箱即用,这不一定是您的情况,但无论如何我都会建议它们。

  1. Obtain accounts with limited permissions from the 3rd party site. In your payment gateway example, an account that allows you to authorize and settle payments, but not to call the TransferToBankAccount($accountNumber) API.

    从第三方网站获取具有有限权限的帐户。在您的支付网关示例中,该帐户允许您授权和结算付款,但不能调用TransferToBankAccount($ accountNumber)API。

    • Similarly, ask the provider to put in restrictions. $accountNumber has to be one of several you've provided or maybe just has to be in the same country as you're located in*.
    • 同样,要求提供商加入限制。 $ accountNumber必须是您提供的几个中的一个,或者只是必须与您位于*中的同一个国家/地区。
  2. Some secure systems rely on a hardware token to provide authentication. (I'm mostly thinking of key-creation and signing dongles.) I'm not sure exactly how this would work in your situation. Assume you've got a dongle that you request the authentication from and it'll only reply under certain circumstances. This is difficult if all it can do is to give (or not give) a username / password. (Vs say, signing a request, where it can examine the request parameters). You could possibly do this with a SSL client certificate, where the request to the 3rd party requires the username / pass / and client signature -- if your 3rd party would accept such a thing.

    某些安全系统依赖硬件令牌来提供身份验证。 (我主要考虑密钥创建和签名加密狗。)我不确定这在你的情况下究竟是如何工作的。假设您有一个加密狗,您要求进行身份验证,它只会在某些情况下回复。如果所能做的只是给(或不给)用户名/密码,这很难。 (比如说,签署一个请求,它可以检查请求参数)。您可以使用SSL客户端证书执行此操作,其中对第三方的请求需要用户名/密码/和客户端签名 - 如果您的第三方接受此类事件。

  3. A combination of #1 and #2. Set up another server to act as a go-between. This server would implement basic business logic that I suggested your 3rd party could do in #1. It exposes an API and checks to make sure that the request is "valid" (payments can be settled, but only outgoing transfers to your account #, etc) before grabbing the auth details and making the request directly. The API can include SetAuthDetails, but not GetAuthDetails. The benefit here is that it's one more thing for the attacker to compromise. And, the simpler the server the easier it is to harden. (No need to run SMTP, FTP, and whatever potentially buggy PHP stack your main server has.... just a few PHP scripts, port 443, SSH, and a, e.g., sqlite instance. Keeping the HTTPD and PHP up to date should be easier because there's less concern about compatibility issues.)

    #1和#2的组合。设置另一台服务器作为中间人。该服务器将实现我建议您的第三方可以在#1中执行的基本业务逻辑。它会公开API并检查以确保请求是“有效”(付款可以结算,但只能传输到您的帐户#等,然后才能获取身份验证详细信息并直接发出请求)。 API可以包含SetAuthDetails,但不包括GetAuthDetails。这样做的好处是攻击者可以妥协的另一件事。而且,服务器越简单就越容易硬化。 (无需运行SMTP,FTP,以及您的主服务器所具有的任何潜在错误的PHP堆栈....只需几个PHP脚本,端口443,SSH和一个例如sqlite实例。保持HTTPD和PHP最新应该更容易,因为对兼容性问题的关注较少。)

  4. Assume you will get compromised and monitor / audit for the potential effects. Have another server somewhere that (yes) has the auth details to log in and check the auth logs (or, ideally, read-only permission). Have it check every minute and check for unauthorized logins and / or transactions and do something drastic (maybe change the password to something random and page you).

    假设您将受到损害并监控/审核潜在影响。在某个地方安装另一台服务器(是)具有登录的auth详细信息并检查auth日志(或理想情况下,只读权限)。让它检查每一分钟并检查未经授权的登录和/或交易,并做一些激烈的事情(可能会将密码更改为随机的内容并为您提供页面)。

*Whether we're actually talking about a payment gateway or not, any 3rd party that you're this concerned about being hacked over should also be concerned about their own security, including if you (or other clients) get hacked. They're also liable to one extent or another, so they should be willing to put in safeguards.

*无论我们是否真的在谈论支付网关,你担心被黑客入侵的任何第三方也应该关注自己的安全性,包括你(或其他客户)被黑客入侵。他们也在某种程度上承担责任,因此他们应该愿意提供保障。

#4


0  

If you use a random salt based on X criteria that you can predict but that a hacker couldn't then depending on how you write the code it still may not be apparent what is what even if the hacker gains access to everything.

如果您使用基于X标准的随机盐,您可以预测,但黑客无法取决于您编写代码的方式,即使黑客获得对所有内容的访问权限,仍然可能不明显是什么。

For example, you use the current time and date plus the users IP address as a salt. You then store those values along with the hash in he database. You obfuscate the function used to create the hash and it might not be so obvious what the salt was. Of course any determined hacker can break that eventually but it buys you time and some additional level of protection.

例如,您使用当前时间和日期加上用户IP地址作为salt。然后,将这些值与哈希值一起存储在数据库中。您混淆了用于创建哈希的函数,并且盐可能不那么明显。当然,任何坚定的黑客最终都可以打破这种局面,但它会为你带来时间和一些额外的保护。

#5


0  

Users are not all very tech savvy but a user, asked to provide credentials for a third party's site, should run away from your site as quick as he can. This is simply a bad idea. The question about storing plaintext passwords definitely applies here, too. Don't do it.

用户并非都非常精通技术,但要求为第三方网站提供凭据的用户应尽快离开您的网站。这简直是​​一个坏主意。关于存储明文密码的问题也适用于此。不要这样做。

You are not providing much context about the third parties in question nor about your relation with them. But you should talk with them about if they are willing to make some changes to support your use case. Them implementing oauth would be a good solution.

您没有提供有关第三方的大量背景信息,也没有提供您与他们的关系。但是,您应该与他们讨论是否愿意进行一些更改以支持您的用例。他们实施oauth将是一个很好的解决方案。

If you want to look around for alternatives, look up federated identity

如果您想环顾四周寻找替代方案,请查看联合身份