gene/module-encryption-key-manager

此软件包最新版本(v0.0.15-alpha)的许可信息不可用。

基因加密密钥管理器

v0.0.15-alpha 2024-08-13 12:40 UTC

README

<genecommerce>

此模块是为了帮助应对 https://sansec.io/research/cosmicsting-hitting-major-stores

来自 sansec 的帖子

升级不足:正如我们之前文章中所警告的,商家升级或应用官方隔离修复至关重要。然而,在此阶段,仅修复 CosmicSting 漏洞可能是不够的。

被盗的加密密钥仍然允许攻击者在升级后生成网络令牌。目前仍然容易受到攻击的商家应将其加密密钥视为已泄露。Adobe 提供了更改加密密钥的功能,同时重新加密现有秘密。

重要提示:使用此功能生成新的加密密钥不会使旧密钥失效。我们建议手动在 app/etc/env.php 中将旧密钥更新为新值,而不是删除它。

即使您的商店已得到保护,也有可能已发布了 JWT,并且它可能仍然有效。强烈建议商家更换加密密钥以确保安全,而 Magento 生成新加密密钥的过程实际上并不会使旧密钥失效。

本模块按原样提供,不提供任何保证。请在本地实例上测试此模块,然后是测试环境,最后是生产环境。自行承担风险使用。

此模块 不会与 Adobe 发布的 新热修复 冲突。本模块和该热修复都以相同的方式提高安全性,即通过使 SecretBasedJwksFactory 使用最新的密钥。此模块还提供了额外的工具和改进,请参阅以下内容。

安装

composer require gene/module-encryption-key-manager
bin/magento setup:upgrade

如何旋转密钥并保护您的商店

以下是一个大致步骤列表,应遵循以防止 CosmicSting 攻击。请仔细阅读所有步骤,以了解此模块提供的功能以及风险点。

生成新密钥并防止旧密钥用于 JWT

这应该是每个商家的 首要任务! 安装此模块并使用以下命令生成新密钥:

php bin/magento gene:encryption-key-manager:generate [--key=MY_32_CHAR_CRYPT_KEY] [--skip-saved-credit-cards]

这将强制 JWT 工厂使用新生成的密钥。应用程序的其他部分可能继续使用旧密钥。此步骤是绝对首要的,并将有助于防止 CosmicSting 攻击。

  • 使用 --key 选项手动定义重新加密期间使用的密钥。如果没有提供自定义密钥,则将生成新密钥。
  • 使用 --skip-saved-credit-cards 标志跳过重新加密 sales_order_payment cc_number_enc 数据。此表可能非常大,许多商店在此列中可能没有任何数据保存。

完全旋转旧密钥

您可以根据需要完成以下操作。只要您已安装独立补丁并使用此模块生成新的加密密钥,您就安全免受cosmicsting的威胁。

然后您可以自由决定是否要重新加密旧数据,并使旧密钥无效。

  1. 审查数据库(确保zgrep版本为1.12)中具有加密值的任何表。请确保您的转储设置为--human-readable(magerun)或--extended-insert=FALSE(mysqldump),以便所有值都位于与INSERT INTO相同的行上。
$ zgrep -P "VALUES\s*\(.*\d:\d:...*'" database.sql | awk '{print $3}' | uniq
admin_user
core_config_data
customer_entity
oauth_token
oauth_consumer
tfa_user_config
admin_adobe_ims_webapi
adobe_user_profile

或获取所有找到的表及其记录数的概览。

zgrep -P "VALUES\s*\(.*\d:\d:...*'" database.sql | awk '{print $3}' | sort | uniq -c
  1. 审查env.php,如果您在那里存储任何加密值,它们可能已被泄露,需要提供商重新发布。
  2. 审查使用加密类中的->hash()函数的functions。更改密钥将导致不同的哈希值。
  3. 如果您有处理此问题的custom logic,则需要手动解决。
  4. 生成新的密钥 php bin/magento gene:encryption-key-manager:generate
    1. 您可以使用php bin/magento gene:encryption-key-manager:generate --key=MY_32_CHAR_CRYPT_KEY指定要使用的新加密密钥。
    2. Magento\Catalog\Model\View\Asset\Image将继续在索引0处使用密钥。
    3. Magento\JwtUserToken\Model\SecretBasedJwksFactory将只使用最新生成的密钥,索引最高。
  5. 修复缺失的配置值 php bin/magento gene:encryption-key-manager:reencrypt-unhandled-core-config-data
    1. 重新运行以验证php bin/magento gene:encryption-key-manager:reencrypt-unhandled-core-config-data
  6. 修复双因素认证数据 php bin/magento gene:encryption-key-manager:reencrypt-tfa-data
    1. 重新运行以验证php bin/magento gene:encryption-key-manager:reencrypt-tfa-data
  7. 修复所有其他已识别的列,例如,请务必验证每个表和列,因为这可能不是完整的列表(还要注意entity_idrow_idid
    1. php bin/magento gene:encryption-key-manager:reencrypt-column admin_user user_id rp_token
    2. php bin/magento gene:encryption-key-manager:reencrypt-column customer_entity entity_id rp_token
    3. php bin/magento gene:encryption-key-manager:reencrypt-column oauth_token entity_id secret
    4. php bin/magento gene:encryption-key-manager:reencrypt-column oauth_consumer entity_id secret
    5. php bin/magento gene:encryption-key-manager:reencrypt-column admin_adobe_ims_webapi id access_token
    6. php bin/magento gene:encryption-key-manager:reencrypt-column adobe_user_profile id access_token
  8. 刷新缓存 php bin/magento cache:flush
  9. 此时,您应该已将所有数据迁移到新的加密密钥,为了帮助您验证这一点,您可以执行以下操作
    1. php bin/magento config:set --lock-env dev/debug/gene_encryption_manager_only_log_old_decrypts 1
    2. php bin/magento config:set --lock-env dev/debug/gene_encryption_manager_enable_decrypt_logging 1
    3. 监控您的日志以查找“gene encryption manager”,以验证是否仍有任何内容仍在使用旧密钥
  10. 当您满意时,可以使旧密钥无效 php bin/magento gene:encryption-key-manager:invalidate
    1. Magento\Catalog\Model\View\Asset\Image将继续在crypt/invalidated_key部分的索引0处使用密钥。
  11. 测试,测试,测试!您的测试重点包括
  • 使用Magento的API的所有集成
  • 您的媒体应该仍然以相同的哈希目录显示。如果它正在重新生成,它将占用大量的磁盘空间和运行时间。
  • 管理员用户登录/注销
  • 客户登录/注销

功能

在生成新密钥时自动使旧JWT无效

当magento生成新加密密钥时,它仍然允许使用JWT使用旧密钥。本模块通过更新\Magento\JwtUserToken\Model\SecretBasedJwksFactory来阻止这一点,以仅允许针对最新加密密钥生成的密钥。

我们注入了一个包装的\Gene\EncryptionKeyManager\Model\DeploymentConfig,它只返回最新的加密密钥。这意味着当生成新加密密钥时,任何现有令牌都不再可使用。

允许您保留现有的媒体缓存目录

当magento生成新的加密密钥时,会导致产品媒体缓存哈希值改变。这会导致所有产品媒体重新生成,消耗大量处理时间,可能会减慢顾客的页面加载速度,同时也消耗额外的磁盘空间。本模块确保媒体库仍然使用旧哈希值。

Magento将调整大小后的产品图像存储在如media/catalog/product/cache/abc123/f/o/foobar.jpg这样的目录中,哈希值abc123是通过系统中的加密密钥生成的。

为了避免在循环加密密钥时需要重新生成所有产品媒体,这里有一些更改以强制继续使用原始值。

Magento\Catalog\Model\View\Asset\Image$encryptor替换为Gene\EncryptionKeyManager\Service\InvalidatedKeyHasher。这使得您可以使用旧密钥继续生成md5哈希值。

防止长时间运行的过程更新订单付款

此模块还将修复一个问题,即在密钥生成过程中会更新每个sales_order_payment条目。在大型商店中,这可能需要很长时间。现在,只有包含已保存卡片信息的必要条目才会更新。

日志记录

本模块提供了一种机制来记录每次解密调用的来源。由于magento系统配置被加密,因此每个请求都会触发日志写入,因此这将产生大量数据。

建议在您处理了系统中所有数据的重新加密之后启用此日志记录,但在使旧密钥无效之前。
这将向您提供一个指示,表明您已经妥善处理了一切,因为如果看到日志被写入,它将告诉您有什么被遗漏以及如何找到问题的来源。

php bin/magento config:set --lock-env dev/debug/gene_encryption_manager_only_log_old_decrypts 1
php bin/magento config:set --lock-env dev/debug/gene_encryption_manager_enable_decrypt_logging 1

日志文件位于 <mage_dir>/var/log/gene_encryption_key.log

bin/magento gene:encryption-key-manager:generate

您可以使用php bin/magento gene:encryption-key-manager:generate来生成新的加密密钥

此CLI工具执行与\Magento\EncryptionKey\Controller\Adminhtml\Crypt\Key\Save::execute()相同的任务,但进行了一些调整

  • 避免不必要的操作空sales_order_payment cc_number_enc值。这在大型商店中很有帮助,其中此表包含许多条目。
$ php bin/magento gene:encryption-key-manager:generate --force
Generating a new encryption key
_reEncryptSystemConfigurationValues - start
_reEncryptSystemConfigurationValues - end
_reEncryptCreditCardNumbers - start
_reEncryptCreditCardNumbers - end
Cleaning cache
Done
  • 使用 --key 选项手动定义重新加密期间使用的密钥。如果没有提供自定义密钥,则将生成新密钥。
  • 使用 --skip-saved-credit-cards 标志跳过重新加密 sales_order_payment cc_number_enc 数据。此表可能非常大,许多商店在此列中可能没有任何数据保存。
  • 这将自动重新加密app/etc/env.php中所有system值。

bin/magento gene:encryption-key-manager:invalidate

您可以使用php bin/magento gene:encryption-key-manager:invalidate来使旧密钥无效

这将创建一个新的部分来存储env.php中的旧invalidated_key,以及将crypt/key路径用无意义文本替换,以保持密钥的数值顺序。

在使无效之前

    'crypt' => [
        'key' => '84c9d7c0b305adf9ea7e19a05478bf11
2951b41e2b7f4c26e60a8e7ee00ca17b'
    ],

在使无效之后

    'crypt' => [
        'key' => 'invalidpwecbVeGpoL3Jxa4PXEOdn1ej
2951b41e2b7f4c26e60a8e7ee00ca17b',
        'invalidated_key' => '84c9d7c0b305adf9ea7e19a05478bf11'
    ],

bin/magento gene:encryption-key-manager:reencrypt-unhandled-core-config-data

当magento生成新的加密密钥时,它会重新加密core_config_data中定义的backend_modelMagento\Config\Model\Config\Backend\Encrypted的值。可能某些第三方模块没有正确实现此功能并自行处理了解密。在这些情况下,我们需要强制通过重新加密过程。

默认情况下,此命令以dry run模式运行,作为第一次运行,以查看将要进行的更改。当您满意时,使用--force运行。

$ php bin/magento gene:encryption-key-manager:reencrypt-unhandled-core-config-data
Run with --force to make these changes, this will run in dry-run mode by default
The latest encryption key is number 14, looking for old entries
################################################################################
config_id: 1347
scope: default
scope_id: 0
path: yotpo/settings/secret
updated_at: 2023-08-31 12:48:27
ciphertext_old: 0:2:abc123
plaintext: some_secret_here
ciphertext_new: 14:3:xyz456
Dry run mode, no changes have been made
################################################################################
Done

bin/magento gene:encryption-key-manager:reencrypt-column

这允许您针对特定列进行重新加密。如果列包含JSON,您可以使用点表示法:column.field

默认情况下,此命令以dry run模式运行,作为第一次运行,以查看将要进行的更改。当您满意时,使用--force运行。

您应确定所有需要处理的列,并通过此过程运行它们。

$ bin/magento gene:encryption-key-manager:reencrypt-column customer_entity entity_id rp_token
Run with --force to make these changes, this will run in dry-run mode by default
The latest encryption key is number 1, looking for old entries
Looking for 'rp_token' in 'customer_entity', identified by 'entity_id'
########################################################################################################################
entity_id: 9876
ciphertext_old: 0:3:54+QHWqhSwuncAa87Ueph7xF9qPL1CT6+M9Z5AWuup447J33KGVw+Q+BvVLSKR1H1umiq69phKq5NEHk
plaintext: acb123
ciphertext_new: 1:3:Y52lxB2VDnKeOHa0hf7kG/d15oooib6GQOYTcAmzfuEnhfW64NAdNN4YjRrhlh2IzQBO5IbwS48JDDRh
Dry run mode, no changes have been made
########################################################################################################################
Done

bin/magento gene:encryption-key-manager:reencrypt-tfa-data

此命令重新加密存储在tfa_user_config中的2FA数据。其中一些数据是双重加密的,因此需要特殊处理。

默认情况下,此命令以dry run模式运行,作为第一次运行,以查看将要进行的更改。当您满意时,使用--force运行。

此CLI工具仅在Google Authenticator (TOTP)和U2F (Yubikey等)上进行测试。如果您使用Authy或DUO,您必须在使用前进行验证。

$ bin/magento gene:encryption-key-manager:reencrypt-tfa-data
Run with --force to make these changes, this will run in dry-run mode by default
This CLI has only been tested with Google Authenticator (TOTP) and U2F (Yubikey, etc). If you use Authy or DUO you *MUST* verify before use.
The latest encryption key is number 1, looking for old entries
Looking for encoded_config in tfa_user_config, identified by 'config_id'
########################################################################################################################
config_id: 1
ciphertext_old: 0:3:rV/z9+ilmOtaPGnOoZBayZ3waBNphK1RAcyWLetipM5UONn793rTyRknO1GhWxKxXC3ooJAgWDTMJPaXGRMGdj8yOqrlrjEp9uqi8D9SFgE/UTiWkBF4RRwVvZeo4lGGnll/CxJmtzuMXWa65TS0Z/a2QLdPyIH/3OomJH7sb3FgfQ==
plaintext_old: {"google":{"secret":"0:3:LKm9642Rpl0gqlBha+m3FYWnQBBtLgjdLDvjfoPo923xmxd9ykbnvX0LucKI","active":true}}
plaintext_new: {"google":{"secret":"1:3:m9mScDkTkeCdn2lXpwf5oMkL7lmgLOTYJXQyKbK\/m8QwDZVDNWI3CzH+uBaq","active":true}}
ciphertext_new: 1:3:Tw/5ik2meBqzL8oodrudxmksrOekA/DbZE5+KgBAygFxp6Zx/A7vbMyHt4+N1MtQhlnqW/mAXL3l2kDpFHIQVvi2L+23o9mRpii2ldBwmuZgDlpQsm+Q4Hf8a+t2aUKndGOMeoH6xcZXFCConC+TUI+uregFXx6B5LU4ohCY52m/v7w=
Dry run mode, no changes have been made
########################################################################################################################
Done

bin/magento gene:encryption-key-manager:get-cloud-keys

此命令用于获取重新加密的云环境变量。这个命令不会更新现有值,它只是在控制台返回新值。开发者需要手动在云控制台中更新这些值。

# No keys example
$ bin/magento gene:encryption-key-manager:get-cloud-keys
There is no old encrypted environment variables found

# There is some encoded
$ bin/magento gene:encryption-key-manager:get-cloud-keys --show-decrypted
There is no old encrypted environment variables found
The CLI command doesn\'t rewrite values. You have to update them manually in cloud console!
Rows count: 4
##################################################################
Name: CONFIG__DEFAULT__SOME_KEY
Dectypted value: dectypted_value
Old Encrypted Value: 0:3:AAA1
New Encrypted Value: 1:3:BBB1
##################################################################
Name: CONFIG__DEFAULT__SOME_KEY_2
Dectypted value: dectypted_value_2
Old Encrypted Value: 0:3:AAA2
New Encrypted Value: 1:3:BBB2

注意事项

report.WARNING:无法反序列化值

这种情况不常见,由使用此模块和使用管理员控制器旋转加密密钥的人报告。刷新Redis缓存可以解决问题。

请确保您刷新Redis缓存

现在您可以继续进行如上所述的重新加密工作。

您已手动更换了加密密钥

您需要

  1. 恢复旧加密密钥
  2. 将旧密钥添加到新密钥之前,用\n分隔,并重复上述步骤

其他问题

搜索https://github.com/genecommerce/module-encryption-key-manager/issues以获取其他问题。