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

不幸的是,这不像密码/散列情况,因为用户每次都不输入凭据 – 它们输入一次,然后将其保存在服务器上以备将来由应用程序使用.

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

如果社区决定了一些好的解决方案,那么将其他来源收集到示例/教程/更多的深度信息中是非常好的,以便将来可以为每个人实现.

我很惊讶,我没有看到这个问题与堆栈上的任何好的答案已经.我确实找到了这个,但在我的情况下,这并不适用于:How should I ethically approach user password storage for later plaintext retrieval?

感谢所有

根据我在问题,答案和评论中可以看到的内容;我建议利用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.

这是从这个评论,并且假设访问您要存储的数据可以放在cron作业中.进一步假设您的服务器上具有SSL(https),因为您将处理机密用户信息,并且可以使用OpenSSL和mcrypt模块.另外,下面的内容将是相当通用的,“如何”实现了,但不是真正的细节,做你的情况.还应该指出,这个“如何”是一般的,你应该在实施之前做更多的研究.话虽如此,让我们开始吧.

首先,我们来谈谈OpenSSL提供的内容. OpenSSL为我们提供了一个Public-Key Cryptography:使用公钥加密数据的能力(如果受到威胁,则不会危及使用其加密的数据的安全性).其次,它提供了一种使用“私钥”访问该信息的方法.由于我们不关心创建证书(我们只需要加密密钥),所以可以使用一个简单的函数获得这些证书(您只需要使用一次).

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发布).我将假定有多个字段需要存储,而且我们只想要要加密一次,它将在一个可以为serialize的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;

}

这个特定的功能将产生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,$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,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,$data,$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,-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;
}

这些中的$数据将始终是一次性填充,而不是用户信息.接下来,将加密和解密的一次性加密密钥加密和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;
}

我保留了这些意见,以帮助了解这些功能.现在是我们得到有趣的部分,实际上是使用用户数据. 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中,然后使用curl将私钥发布到正在寻找的页面. (确保您打电话以https开头的地址)

希望能帮助您回答如何将用户信息安全地存储在应用程序中,而不必通过访问您的代码或数据库来损害用户信息.

php – 如何保护API密钥和第三方站点凭据(LAMP)?的更多相关文章

  1. canvas中普通动效与粒子动效的实现代码示例

    canvas用于在网页上绘制图像、动画,可以将其理解为画布,在这个画布上构建想要的效果。本文详细的介绍了粒子特效,和普通动效进行对比,非常具有实用价值,需要的朋友可以参考下

  2. H5混合开发app如何升级的方法

    本篇文章主要介绍了H5混合开发app如何升级的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  3. canvas学习和滤镜实现代码

    这篇文章主要介绍了canvas学习和滤镜实现代码,利用 canvas,前端人员可以很轻松地、进行图像处理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  4. localStorage的过期时间设置的方法详解

    这篇文章主要介绍了localStorage的过期时间设置的方法详解的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  5. 详解HTML5 data-* 自定义属性

    这篇文章主要介绍了详解HTML5 data-* 自定义属性的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  6. HTML5的postMessage的使用手册

    HTML5提出了一个新的用来跨域传值的方法,即postMessage,这篇文章主要介绍了HTML5的postMessage的使用手册的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. 教你使用Canvas处理图片的方法

    本篇文章主要介绍了教你使用Canvas处理图片的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  8. ios – Swift语言:如何调用SecRandomCopyBytes

    从Objective-C,我可以这样做:在Swift中尝试这个时,我有以下内容:但我得到这个编译器错误:data.mutableBytes参数被拒绝,因为类型不匹配,但我无法弄清楚如何强制参数.解决方法这似乎有效:

  9. 使用Firebase iOS Swift将特定设备的通知推送到特定设备

    我非常感谢PushNotifications的帮助.我的应用聊天,用户可以直接向对方发送短信.但是如果没有PushNotifications,它就没有多大意义.它全部设置在Firebase上.如何将推送通知从特定设备发送到特定设备?

  10. ios – NSData to Data swift 3

    如何将此代码转换为使用Swift3数据?

随机推荐

  1. PHP个人网站架设连环讲(一)

    先下一个OmnihttpdProffesinalV2.06,装上就有PHP4beta3可以用了。PHP4给我们带来一个简单的方法,就是使用SESSION(会话)级变量。但是如果不是PHP4又该怎么办?我们可以假设某人在15分钟以内对你的网页的请求都不属于一个新的人次,这样你可以做个计数的过程存在INC里,在每一个页面引用,访客第一次进入时将访问时间送到cookie里。以后每个页面被访问时都检查cookie上次访问时间值。

  2. PHP函数学习之PHP函数点评

    PHP函数使用说明,应用举例,精简点评,希望对您学习php有所帮助

  3. ecshop2.7.3 在php5.4下的各种错误问题处理

    将方法内的函数,分拆为2个部分。这个和gd库没有一点关系,是ecshop程序的问题。会出现这种问题,不外乎就是当前会员的session或者程序对cookie的处理存在漏洞。进过本地测试,includes\modules\integrates\ecshop.php这个整合自身会员的类中没有重写integrate.php中的check_cookie()方法导致,验证cookie时返回的username为空,丢失了登录状态,在ecshop.php中重写了此方法就可以了。把他加到ecshop.php的最后面去就可

  4. NT IIS下用ODBC连接数据库

    $connection=intodbc_connect建立数据库连接,$query_string="查询记录的条件"如:$query_string="select*fromtable"用$cur=intodbc_exec检索数据库,将记录集放入$cur变量中。再用while{$var1=odbc_result;$var2=odbc_result;...}读取odbc_exec()返回的数据集$cur。最后是odbc_close关闭数据库的连接。odbc_result()函数是取当前记录的指定字段值。

  5. PHP使用JpGraph绘制折线图操作示例【附源码下载】

    这篇文章主要介绍了PHP使用JpGraph绘制折线图操作,结合实例形式分析了php使用JpGraph的相关操作技巧与注意事项,并附带源码供读者下载参考,需要的朋友可以参考下

  6. zen_cart实现支付前生成订单的方法

    这篇文章主要介绍了zen_cart实现支付前生成订单的方法,结合实例形式详细分析了zen_cart支付前生成订单的具体步骤与相关实现技巧,需要的朋友可以参考下

  7. Thinkphp5框架实现获取数据库数据到视图的方法

    这篇文章主要介绍了Thinkphp5框架实现获取数据库数据到视图的方法,涉及thinkPHP5数据库配置、读取、模型操作及视图调用相关操作技巧,需要的朋友可以参考下

  8. PHP+jquery+CSS制作头像登录窗(仿QQ登陆)

    本篇文章介绍了PHP结合jQ和CSS制作头像登录窗(仿QQ登陆),实现了类似QQ的登陆界面,很有参考价值,有需要的朋友可以了解一下。

  9. 基于win2003虚拟机中apache服务器的访问

    下面小编就为大家带来一篇基于win2003虚拟机中apache服务器的访问。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  10. Yii2中组件的注册与创建方法

    这篇文章主要介绍了Yii2之组件的注册与创建的实现方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下

返回
顶部