LIBSODIUM像使用AES_DECRYPT一样在mysql查询中解密数据

时间:2018-08-24 08:51:15

标签: php mysql security encryption libsodium

我有一些SQL查询,其中我选择了靠近用户位置的行。 使用AES_DECRYPT,我可以在查询中进行操作:

AES_DECRYPT(lat, :key)

我需要查询中的解密值:
1.订购
2.分隔给定区域中的条目
3.和其他查询类似的东西

一个查询的简短示例:

SELECT something,
(
    6371 * acos( cos( radians(".$userdatafromdbfetchedbefore['lat'].") ) * cos( radians( AES_DECRYPT(lat, :key) ) ) * cos( radians( AES_DECRYPT(lng, :key) ) - radians(".$userdatafromdbfetchedbefore['lng'].") ) + sin( radians(".$userdatafromdbfetchedbefore['lat'].") ) * sin(radians( AES_DECRYPT(lat, :key))) )
) AS distance
FROM 
    table
HAVING 
    distance <= ".$userdatafromdbfetchedbefore['maxrange']."
ORDER BY 
    e.orderdate 
DESC,
    distance  
ASC
LIMIT
    ".$start.", ".$offset."

我无法选择其他查询上的所有行并使用php操作结果,这对于100k +行来说是非常低效的,而用户附近的行可能只有〜100。

对位置数据进行加密对我来说非常重要,因为到目前为止,由于不安全的加密,我没有启动我的项目。

现在我的问题是我如何使用新的php实现的Libsodium做同样的事情?

我找不到一个可行的例子。我刚刚找到了一个带有盲索引的示例,在该示例中,如果像对存储的术语一样对搜索词进行加密,则可以找到一个值,但是在我的情况下这没有帮助,因为我需要获取该值才能通过同一表达式中的距离公式来运行该值查询。

1 个答案:

答案 0 :(得分:2)

Libsodium不是MySQL内置的,因此您不能只从MySQL查询中调用与AES_ENCRYPT()等效的东西并获得您期望的结果。

但是,另一种方法是使用类似CipherSweet的库,该库提供可搜索的经过身份验证的加密。在决定使用它们之前,请确保您了解its featureslimitations

<?php
use ParagonIE\CipherSweet\CipherSweet;
use ParagonIE\CipherSweet\EncryptedRow;
use ParagonIE\CipherSweet\Transformation\AlphaCharactersOnly;
use ParagonIE\CipherSweet\Transformation\FirstCharacter;
use ParagonIE\CipherSweet\Transformation\Lowercase;
use ParagonIE\CipherSweet\Backend\FIPSCrypto;
use ParagonIE\CipherSweet\KeyProvider\StringProvider;

$provider = new StringProvider(
    // Example key, chosen randomly, hex-encoded:
    'a981d3894b5884f6965baea64a09bb5b4b59c10e857008fc814923cf2f2de558'
);
$engine = new CipherSweet($provider, new FIPSCrypto());

/** @var CipherSweet $engine */
$row = (new EncryptedRow($engine, 'contacts'))
    ->addTextField('first_name')
    ->addTextField('last_name')
    ->addFloatField('latitude')
    ->addFloatField('longitude');

// Notice the ->addRowTransform() method:
$row->addCompoundIndex(
    $row->createCompoundIndex(
        'contact_first_init_last_name',
        ['first_name', 'last_name'],
        64, // 64 bits = 8 bytes
        true
    )
        ->addTransform('first_name', new AlphaCharactersOnly())
        ->addTransform('first_name', new Lowercase())
        ->addTransform('first_name', new FirstCharacter())
        ->addTransform('last_name', new AlphaCharactersOnly())
        ->addTransform('last_name', new Lowercase())
);

$prepared = $row->prepareRowForStorage([
    'first_name' => 'Jane',
    'last_name' => 'Doe',
    'latitude' => 52.52,
    'longitude' => -33.106,
    'extraneous' => true
]);

var_dump($prepared);

您应该看到与此类似的内容。 [0]中的值将更改,但[1]中的值将保持不变。这是因为[0]包含行数据(某些字段已加密)。 [1]仅包含盲索引(稍后可在SELECT查询中使用)。

array(2) {
  [0]=>
  array(5) {
    ["first_name"]=>
    string(141) "fips:nrtzoaxvPIOA7jPskWVwJmC0q8WJqrsnqjPh3ifNPsRd2TAx6OwTDfSiMVCXSsSRNQb_nxJlW7TbAtf5UvQRWWKTGhk_kXxpZKdnTrpjbmxi0IgstSrZ126Qz6E0_lvjew0Ygw=="
    ["last_name"]=>
    string(137) "fips:98f5CLB24w0zSqCGPR0D2oq9wQvUwzxo_byAp6mKgMgoJkUHZX1oTtk4Cm8FXI7fsUI8HOG5sKQFGRn6cXMw1EOMGgpXZqiXEDb3jxEbg9s95d4g2NeVd4xs2tmX0xlZ0nSM"
    ["latitude"]=>
    string(145) "fips:d3TVGfnRFlvWxbfihgHqjpXlXU3HtkCAHzM0-4f1l5dAeQf2Vk5RDDVOGMQNM09r0O4UOAub6QTyHGezQ0bWKQ5omqoYCTBJE0Uf_2DSPfO7U4dG74phaP04iFgqpJ8G41q54Kv5t54="
    ["longitude"]=>
    string(145) "fips:IcnUnBZZOxJPYXk-F3v12O_krNb9JsexljiV4gJzgctTpxLFm7ql0tJRF7xP3wLrUtd1VyfYBf75ot7iOSIIIFqsuyKZQdI9UyKbqd87RTMsHbHgPouxgZBg1urlqpuWqbOYEFGiti4="
    ["extraneous"]=>
    bool(true)
  }
  [1]=>
  array(1) {
    ["contact_first_init_last_name"]=>
    array(2) {
      ["type"]=>
      string(13) "w6dsrxbathjze"
      ["value"]=>
      string(16) "546b1ffd1f83c37a"
    }
  }
}

请注意,即使输入的精度有所不同,浮点字段也将始终生成固定长度的输出。这样做是为了防止攻击者从密文长度中学习信息。

如果选择ModernCrypto instead of FIPSCrypto,以上所有操作都将使用libsodium完成。如果有人好奇的话,每个人使用的确切加密是documented here


请注意,您必须对PHP中而不是SQL中的解密值进行自己的计算。

毕竟,在将数据存储到数据库之前对其进行加密的全部目的是将其隐藏在数据库服务器(以及可能损害该服务器的所有攻击者)中。