Как вы защищаете ключи API и учетные данные стороннего сайта (LAMP)?

Я создаю сайт, который будет использовать идентификаторы, пароли и ключи API для других сторонних сайтов, чтобы сервер мог соответственно получить доступ к информации. Для целей этого разговора предположим, что это для платежного шлюза - это означает, что раскрытие этой информации, хранящейся в БД, может означать, что злоумышленник может снять наличные со счета, учетные данные которого были утекли.

К сожалению, это не похоже на ситуацию с паролем / хешированием, потому что пользователь не вводит учетные данные каждый раз - они вводят их один раз, а затем они сохраняются на сервере для будущего использования приложением.

Единственный разумный метод, который я могу придумать (это будет приложение MySQL / PHP), - это зашифровать учетные данные с помощью жестко запрограммированного «пароля» в приложении PHP. Единственное преимущество здесь состоит в том, что если злоумышленник / хакер получает доступ к базе данных, но не к коду PHP, у них все равно ничего не будет. Тем не менее, это кажется мне бессмысленным, потому что я думаю, мы можем разумно предположить, что хакер получит все, если получит то или другое - верно?

Если сообщество примет решение о некоторых хороших решениях, было бы неплохо собрать другие источники для примеров / руководств / более подробной информации, чтобы это можно было реализовать в будущем для всех.

Я был удивлен, что не увидел в стеке этого вопроса с хорошими ответами. Я нашел это, но в моем случае это действительно не применимо: Как мне этично подойти к хранению паролей пользователей для последующего извлечения открытого текста?

Спасибо всем.


person Shackrock    schedule 02.03.2013    source источник
comment
Ваша награда требует обсуждения. Прочтите часто задаваемые вопросы; ТАК не обсуждается.   -  person Amelia    schedule 09.03.2013
comment
также используйте oauth. это безопасно.   -  person Amelia    schedule 09.03.2013
comment
@Hiroto Извините за это повторное обсуждение, в любом случае я возьму правильный ответ, если кто-то подойдет и узнает о награде. oauth указывает OAuth provides a method for users to grant third-party access to their resources without sharing their passwords. It also provides a way to grant limited access (in scope, duration, etc.). Для описанной ситуации (например, для обработки платежей) серверу требуется неограниченный доступ к этим API в любое время по разным причинам. Я не вижу, как это могло бы улучшить ситуацию - общий пароль не обязательно является проблемой.   -  person Shackrock    schedule 09.03.2013
comment
Просто чтобы добавить, служба, которую я буду использовать, не поддерживает oAth =), как и многие сайты.   -  person Shackrock    schedule 10.03.2013


Ответы (5)


На основании того, что я вижу в вопросе, ответах и ​​комментариях; Я бы посоветовал воспользоваться OpenSSL. Предполагается, что вашему сайту требуется периодический доступ к этой информации (то есть это может быть запланировано). Как вы заявили:

Эта информация потребуется серверу для отправки платежей в самых разных ситуациях. Для этого не требуется, чтобы «владелец» указанных ключей входил в систему, на самом деле владелец никогда не захочет увидеть их снова, как только они предоставят их в первый раз.

Именно из этого комментария и предположения, что доступ к данным, которые вы хотите сохранить, можно поместить в задание cron. Кроме того, предполагается, что у вас есть SSL (https) на вашем сервере, поскольку вы будете иметь дело с конфиденциальной информацией пользователя, и у вас есть модули OpenSSL и mcrypt. Кроме того, нижеследующее будет довольно общим относительно того, «как» это может быть достигнуто, но на самом деле это не детали того, как это сделать в вашей ситуации. Также следует отметить, что это «практическое руководство» является общим, и вам следует провести дополнительные исследования, прежде чем применять его. При этом, давайте начнем.

Во-первых, давайте поговорим о том, что предоставляет 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;
}

Теперь у вас есть открытый и закрытый ключ. Защитите закрытый ключ, храните его на сервере и не допускайте попадания в базу данных. Храните его на другом сервере, компьютере, который может запускать задания cron и т. Д. Просто нигде рядом с общественностью, если только вы не можете требовать, чтобы администратор присутствовал каждый раз, когда вам требуется обработка платежа и зашифровать закрытый ключ с помощью шифрования AES или чего-то еще. похожий. Однако открытый ключ будет жестко запрограммирован в вашем приложении и будет использоваться каждый раз, когда пользователь вводит свою информацию для сохранения.

Затем вам нужно определить, как вы планируете проверять расшифрованные данные (чтобы вы не начинали отправлять в платежные API недопустимые запросы). Я предполагаю, что есть несколько полей, которые необходимо сохранить, и поскольку мы только хотим для однократного шифрования он будет в массиве PHP, который можно сериализовать d. В зависимости от того, сколько данных необходимо сохранить, мы сможем либо зашифровать их напрямую, либо сгенерировать пароль для шифрования с помощью открытого ключа и использовать этот случайный пароль для шифрования самих данных. Я собираюсь пойти этим путем в объяснении. Чтобы пойти по этому пути, мы будем использовать шифрование 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;

}

Эта конкретная функция будет генерировать 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;
}

(Изначально я написал эти функции как часть класса и предлагаю вам реализовать их в собственном классе.) Кроме того, использование этой функции подходит для одноразового блокнота, который создается, однако, если он используется с пароль для конкретного пользователя для другого приложения, вам определенно понадобится немного соли, чтобы добавить к паролю. Затем, чтобы расшифровать и проверить правильность расшифрованных данных:

/**
 * 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;
    }
}

Посмотрите на обе функции, прочтите комментарии и т. Д. Выясните, что они делают и как работают, чтобы вы не реализовали их неправильно. Теперь перейдем к шифрованию пользовательских данных. Мы зашифруем его с помощью открытого ключа, и следующие функции предполагают, что все функции до сих пор (и в будущем) находятся в одном классе. Я предоставлю обе функции шифрования / дешифрования 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;
}

$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;
}

Я оставил комментарии нетронутыми, чтобы облегчить понимание этих функций. А теперь перейдем к самой интересной части, собственно, к работе с данными пользователей. $data в методе send - это данные пользователя в сериализованном массиве. Помните, что для метода отправки $publicKey жестко запрограммирован, вы можете сохранить его как переменную в своем классе и получить к нему доступ таким образом, чтобы меньше переменных передавалось в него, или чтобы он вводился из другого места для отправки в метод каждый раз. Пример использования для шифрования данных:

$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.

Теперь это простая часть, следующая часть - возможность использовать эти данные. Для этого вам понадобится страница на вашем сервере, которая принимает $_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.

Затем конкретная теория использования для доступа к этой защищенной странице с помощью закрытого ключа. На отдельном сервере у вас будет задание cron, которое запускает скрипт php, в частности, не в public_html, содержащий закрытый ключ, а затем используйте _ 18_, чтобы опубликовать закрытый ключ на вашей странице, которая его ищет. (Убедитесь, что вы звоните по адресу, который начинается с https)

Я надеюсь, что это поможет ответить на вопрос, как можно безопасно хранить пользовательскую информацию в вашем приложении, которая не будет скомпрометирована при доступе ни к вашему коду, ни к вашей базе данных.

person Jon    schedule 11.03.2013
comment
Вручение награды. Это наиболее полный и лучший ответ из того, что у нас есть. Спасибо, Джон. - person Shackrock; 15.03.2013
comment
Спасибо! Добро пожаловать ^^ Хотя, судя по этой формулировке, я предполагаю, что это не совсем то, что вы искали? - person Jon; 16.03.2013
comment
Что ж, я думаю, я понимаю, что не может быть способа сделать именно то, о чем я говорю, очень безопасно без сторонней службы (которую обе стороны соглашаются использовать) или чего-то вроде того, что вы описываете здесь, и всего. - person Shackrock; 16.03.2013
comment
Я согласен с этим утверждением. При хранении такого рода информации, особенно если это происходит на ваших собственных серверах, вы должны убедиться, что в случае взлома кода или базы данных информация в нем не будет. Однако с хранением платежной информации можно было бы справиться проще, если бы покупаемые продукты не требовали хранения конфиденциальной информации. Если вы свяжетесь со мной (ссылка в профиле), я буду более чем счастлив обсудить это подробнее о других вариантах, которые вы можете использовать, которые могут помочь в вашей конкретной ситуации, если я знаю, что это за ситуация. ^^ - person Jon; 17.03.2013

Позвольте мне посмотреть, смогу ли я резюмировать проблему, а затем мой ответ на то, что я понимаю в проблеме.

Вы хотите, чтобы пользователи входили в ваше приложение, а затем сохраняли сторонние учетные данные. (Неважно, что это за учетные данные ...) В целях безопасности вы не хотели бы, чтобы был простой способ расшифровать эти учетные данные в случае, если хакер получит доступ к базе данных.

Вот что я предлагаю.

  1. Создайте систему аутентификации, чтобы пользователь мог войти в ваше приложение. Пользователь ДОЛЖЕН входить в систему каждый раз, когда он посещает сайт. При хранении доступа ко всем этим другим учетным данным, «запомнить меня» - просто ужасная идея. Аутентификация создается путем объединения и хеширования имени пользователя, пароля и соли. Таким образом, никакая из этой информации не сохраняется в базе данных.

  2. Хешированная версия комбинации имени пользователя и пароля сохраняется в сеансе. Это становится ГЛАВНЫМ КЛЮЧОМ.

  3. Вводится сторонняя информация. Эта информация зашифрована с помощью хэша MASTER KEY.

Значит, это означает ...

Если пользователь не знает своего пароля, ему не повезло. Однако получить информацию хакеру будет очень сложно. Им нужно будет понять хеширование имени пользователя, пароля, соли, чтобы нарушить аутентификацию, затем иметь эту хешированную версию имени пользователя / пароля для главного ключа, а затем использовать это для расшифровки данных.

Взломать еще можно, но очень сложно - маловероятно. Я бы также сказал, что это дает вам относительную возможность отрицания, потому что, согласно этому методу, вы никогда не узнаете информацию на сервере, поскольку она зашифрована перед сохранением. Этот метод похож на то, как я предполагаю, что работают такие сервисы, как OnePassword.

person Aaron Saray    schedule 09.03.2013
comment
Не совсем. Здесь намерение состоит в том, чтобы сервер использовал эти учетные данные программно. Например, это может быть имя пользователя / пароль платежного API / ключи API. Эта информация потребуется серверу для отправки платежей в самых разных ситуациях. Для этого не требуется, чтобы владелец упомянутых ключей входил в систему, на самом деле владелец никогда не захочет увидеть их снова, как только они предоставят их в первый раз. - person Shackrock; 09.03.2013
comment
Ах, спасибо за разъяснения. Что ж, хотя я не могу сказать, что нельзя сделать лучше, чем предлагали другие, это выходит за рамки того, что я могу предложить. Я не могу представить себе сценарий, в котором ключ шифрования отключен настолько, что скомпрометированный сервер и db по-прежнему делают данные непригодными для использования. Это, конечно, причина, по которой многие службы сейчас используют OAuth. Ненавижу быть тем парнем, который говорит использовать этот инструмент вместо этого !! но, возможно, если безопасность имеет первостепенное значение, вы можете рассмотреть только вспомогательные службы, которые предоставляют доступ к хешированному ключу. - person Aaron Saray; 10.03.2013
comment
@Shackrock Будет ли запланировано использование вводимой пользователем информации? (т.е. позволит ли ваша ситуация произвести все платежи, которые необходимо произвести в течение дня, сразу или поэтапно?) Или в результате их прямого взаимодействия с сайтом? - person Jon; 11.03.2013
comment
@jon Они будут основаны на другом пользовательском вводе. Т.е. другой пользователь производит оплату за продукт, и ключи API / имя пользователя / пароль для человека, чей продукт покупается, получают немедленный доступ, и платеж отправляется. - person Shackrock; 12.03.2013
comment
@Shackrock Тогда не будет чистого способа сделать это на том же сервере, хотя вы можете несколько изменить мой ответ и поместить платеж в очередь (используйте шифрование с открытым ключом в информации CC) и запускать cron каждую минуту или поэтому, чтобы проверить наличие новых платежей, это было бы почти бессмысленным, но потребовало бы, чтобы покупающий пользователь дождался, пока cron обработает платеж, а затем обновит БД, чтобы, если пользователь проверит и увидит, что платеж прошел, и затем может (получить продукт, сделайте загрузку и т. д.) оттуда. - person Jon; 12.03.2013

Есть несколько возможных решений, если вы думаете нестандартно ... и можете действовать нестандартно, что не обязательно в вашем случае, но я все равно собираюсь их предложить.

  1. Получите учетные записи с ограниченными разрешениями на стороннем сайте. В примере с платежным шлюзом - это учетная запись, которая позволяет вам авторизовать и производить платежи, но не вызывать API TransferToBankAccount ($ accountNumber).

    • 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*.
  2. Некоторые защищенные системы полагаются на аппаратный токен для аутентификации. (Я в основном думаю о создании ключей и подписи ключей.) Я не уверен, как именно это сработает в вашей ситуации. Предположим, у вас есть электронный ключ, с которого вы запрашиваете аутентификацию, и он будет отвечать только при определенных обстоятельствах. Это сложно, если все, что он может сделать, это дать (или не дать) имя пользователя / пароль. (Vs, скажем, подписание запроса, где он может проверить параметры запроса). Вы могли бы сделать это с помощью сертификата клиента SSL, где запрос к третьей стороне требует имени пользователя / пароля / и подписи клиента - если ваша третья сторона примет такую ​​вещь.

  3. Комбинация №1 и №2. Настройте другой сервер в качестве посредника. Этот сервер будет реализовывать базовую бизнес-логику, которую я предложил вашей третьей стороне сделать в №1. Он предоставляет API и проверяет, является ли запрос «действительным» (платежи могут быть выполнены, но только исходящие переводы на ваш счет № и т. Д.) Перед получением данных аутентификации и отправкой запроса напрямую. API может включать SetAuthDetails, но не GetAuthDetails. Преимущество здесь в том, что злоумышленник может пойти на компромисс. И чем проще сервер, тем легче его укрепить. (Нет необходимости запускать SMTP, FTP и любой другой потенциально ошибочный стек PHP, который есть на вашем основном сервере .... всего несколько сценариев PHP, порт 443, SSH и, например, экземпляр sqlite. Поддержание HTTPD и PHP в актуальном состоянии должно быть проще, потому что меньше проблем с совместимостью.)

  4. Предположим, что вас скомпрометируют, и отслеживайте / проверяйте возможные последствия. Имейте где-нибудь другой сервер, у которого (да) есть данные аутентификации для входа в систему и проверки журналов аутентификации (или, в идеале, разрешение только на чтение). Попросите его проверять каждую минуту и ​​проверять наличие несанкционированных входов и / или транзакций и делать что-нибудь радикальное (возможно, изменить пароль на что-то случайное и вызвать вас).

* Независимо от того, говорим мы на самом деле о платежном шлюзе или нет, любая третья сторона, которую вас беспокоит взлом, также должна быть обеспокоена своей собственной безопасностью, в том числе в случае взлома вас (или других клиентов). Они также несут ответственность в той или иной степени, поэтому они должны быть готовы принять меры предосторожности.

person James S    schedule 13.03.2013

Если вы используете случайную соль, основанную на критериях X, которые вы можете предсказать, но не мог бы хакер, тогда, в зависимости от того, как вы пишете код, все равно может быть неочевидно, что есть что, даже если хакер получит доступ ко всему.

Например, вы используете текущее время и дату плюс IP-адрес пользователя в качестве соли. Затем вы сохраняете эти значения вместе с хешем в базе данных. Вы запутываете функцию, используемую для создания хэша, и может быть не так очевидно, в чем заключалась соль. Конечно, любой целеустремленный хакер может в конечном итоге это сломать, но это даст вам время и дополнительный уровень защиты.

person Phillip Berger    schedule 02.03.2013
comment
Спасибо. Я думаю, что это то же самое, что хранить какой-то пароль шифрования, жестко закодированный в PHP. Как вы сказали, хакер может выяснить мой метод генерации этого кода, и в конце концов это будет похоже на жестко запрограммированный пароль PHP, но да, это позволяет выиграть время. - person Shackrock; 03.03.2013
comment
Если безопасность критически важна, я бы арендовал второй сервер, единственной задачей которого было хранение базы данных. Таким образом, если хакер взломает ваш код, у него все еще нет информации о базе данных, и наоборот. - person Phillip Berger; 03.03.2013
comment
@aguyfromhere: Если ваш сервер приложений может получить доступ к базе данных, и он будет взломан, то как вы думаете, что хакер не сможет получить доступ к базе данных? :-) - person FtDRbwLXw6; 08.03.2013

Не все пользователи хорошо разбираются в технологиях, но пользователь, которого просят предоставить учетные данные для стороннего сайта, должен как можно скорее сбежать с вашего сайта. Это просто плохая идея. Вопрос о хранении паролей в виде открытого текста здесь определенно актуален. Не делай этого.

Вы не предоставляете подробного контекста ни о третьих сторонах, о которых идет речь, ни о своих отношениях с ними. Но вам следует поговорить с ними о том, хотят ли они внести некоторые изменения для поддержки вашего варианта использования. Их реализация oauth была бы хорошим решением.

Если вы хотите поискать альтернативы, найдите федеративную идентификацию.

person flup    schedule 14.03.2013
comment
Контекст - это платежный процессор и продавец. Например: на сайте много продавцов. Пользователь может покупать у любого из продавцов на сайте. Сайту необходимы учетные данные / ключи API для каждого продавца, чтобы отправлять деньги в нужное место. - person Shackrock; 15.03.2013
comment
Существует множество правил, проверок, аудитов и юридических документов, касающихся безопасности обработки платежной информации. Вы не можете решать, что достаточно безопасно, а что нет. Правила пишут банки и компании, выпускающие кредитные карты. - person flup; 18.03.2013
comment
речь идет не о стандартах PCI, которые можно удовлетворить, просто сохранив эти учетные данные в виде открытого текста в БД. PCI - это безопасность держателей карт. Вопрос касается лучших практик для хранения этой информации о типе учетных данных API / продавца (чтобы нам не приходилось хранить ее в виде открытого текста в БД). - person Shackrock; 18.03.2013