AWS KMS与LARAVEL

2021-03-13 09:27:53

AWS KMS是一个令人难以置信的提供,由AWS管理加密,自动旋转和安全存储。通过启用旋转,AWS将每年生成一次新的加密密钥,而不会删除以前的键。任何由旧密钥生成的密码仍然可以放下折叠。我们无法访问实际键,意思是您无法泄漏它。

Laravel船舶使用AES进行加密的加密类。重新应用Laravel的实现仅用KMS仅占SimpleKMSencrypter和服务提供商。

我刚刚发出了一个拉出请求,将StringEncrypterInterface引入Laravel,以便简化此过程。 https://github.com/laravel/framework/pull/36578.

最终类扩展{公共功能寄存器(){$ this - > app - > Singleton(KMSencrypter :: class,function(){$ key = config(' encryption.key'); $ context = config('加密.Context'); $ client = $ this - > app - > make(kmsclient::class);返回新($客户,$ key,$ context??[]);}; $这个 - > app - >别名(Kmsencrypter :: class,'加密器'); $这个 - > app - >别名(KMSEncrypter :: class,\ illuminate \ contracts \ concryption \ encypter :: class); $这个 - > app - >别名(Kmsencrypter :: class,\ illuminate \ contracts \ encryption \ stringencrypter :: class); }}

请注意我们如何在KMSencrypterfactory回调内实例化KMSClient。这使我们有机会委派如何解决KMSClient到一个单独的过程。这样做的一种方法可能是这样的:

最终类扩展{公共功能寄存器(){$ this - >寄存器3(); $这个 - > registerkms();私人函数寄存器3():void {$ this - > app - >绑定(s3client::class,clusion(){$ region = config(' aws.region');返回新的(['区域' => $地区,'版本' =>' 2006-03-01']);});私人函数regresskms():void {$ this - > app - > bind(kmsclient::class,fn()=> new(['版本'' 2014-11-01','区域' =&gt ;配置(' aws.region')); }}

Final Class实现,stringEncrypter {公共功能__construct(私有KMSClient $客户端,私有字符串$ key,私有数组$上下文){}公共函数加密($ value,$ serialize = true){try {return base64_encode($ this - >客户端 - >加密([' keyid' => $ this - > key,'明文' => $ value,'加密context' => $这个 - >上下文,]) - > get(' ciphertextblob')); catch(awsexception $ e){over new($ e-> getmessage(),$ e-> getcode(),$ e);公共功能解密($ payload,$ underalize = true){try {$结果= $ this - >客户 - >解密([' ciphertextblob' => base64_decode($ puyload),'加密context' => $ this - >上下文,]);返回$结果['明文' ]; catch(awsexception $ e){over new($ e-> getmessage(),$ e-> getcode(),$ e);公共函数加密(String $ Value):String {return $ this - >加密($ value,false); public function decrypttring(string $ value):string {return $ this - >解密($ VALUE,FALSE); }}

让我们解剖这个课程。首先,我们拥有KMSClient ComaLeady携带InterActwits KMS所需的每个配置。无论您是使用AWSCredentials的环境变量,还是让您的AWS服务使用Permisions与KMS交互,AWS SDK都将处理身份验证。然后我们的键应该是要使用的键的AWS KMS Keyor别名的ARN。最后,我们有背景。 Contextis是非秘密信息(例如,它将是CloudTrail上的纯文本),允许您使用特定的签名Context绑定加密。如果在尝试解密特定密码时未提供完全相同的上下文,则解密将不作。例如,您可以选择使用您的Service Name的加密上下文,以便如果其他服务意外用于解密您的密码,则它不仅仅是工作。 Developer必须在尝试解密交叉服务数据时进行有意识地指定另一个Service Scontext。

为易于使用,我们可以在解密之前base64_encode()base64_encode()ciphet文本,然后在base64_decode之前,使其更容易绕过数据。如果您有兴趣了解有关Base64_Encode的更多信息,请查看我的帖子,我应该加密,哈希或编码吗?

由于ServiceProvider正在更换Encypteron Laravel服务提供商背后的绑定,因此我们可以自动使用EloQuent'Cast功能自动加密/解密属性。

最终类扩展{受保护$ casts = ['密码' => '加密' ,' client_secret' => '加密' ,]; }

以这种方式,只要我们尝试将某些东西保存到密码或Client_secret属性中,Eloquent将使用KMSencrypter Toencrypt存储的数据以及当我们访问该属性时,EloQuent Mutators将启用并解密它。

对于我的自动化测试,我决定使用nullencrypter实现,即我不需要直接与AWS KMS集成到Runtests。这是如何看起来像Nullencrypter的样子:

最终类实现{公共函数加密(String $ Value):String {return $ this - >加密($ value,false); public function decrypttring(string $ value):string {return $ this - >解密($ VALUE,FALSE);公共函数加密($ value,$ serialize = true){返回$ value;公共功能解密($ payload,$ unsemalize = true){return $ payload; }}

在这种实施的发展中,我首先在没有加密的情况下写下了一个Produtfeature并将API交给了Frontendteam,以便他们可以开始。然后我开始实现了KMS加密。我注意到,随时我的代码会尝试解密密文,它会抛出一个例外说法

执行"解密" On" https://kms.eu-west-1.amazonaws.com" ;; AWS HTTP错误:客户端错误:`post https:// kms.eu-west-1.Amazonaws.com`导致在一个400糟糕的请求中响应:{" __类型":" InvalidCipherTextException"} InvalidCipherTextException(客户): - {" __类型":" InvalidCipherTextException&# 34;}

我获得此错误的原因不是因为上下文的keynor。它实际上是因为我正在使用Strict = false和一个密码字段互动,rype varchar(191)。然后发生的是,密码文本转向191以上的字符和MySQL将截断数据显示为191个字符。丢失密码的一部分意味着我们没有保证消息的完整性,我们加油更长的解密。增加现场尺寸减轻了刺痛。

为什么我们不通知密钥解密API调用AWS?

当AWS加密有效载荷时,它会在密码文本中放入密钥用于加密。这样偶数我们不知道哪个密钥用于加密,只要您拥有完整的密文和Thecontext,AWS仍然可以解密它。这可能有助于在旋转键时促进AWS的工作。当关键达到1年的生命中时,AWS将生成一个品牌的兴新机,并开始使用它进行任何新的加密。但是,它不会摆脱旧密钥。因此,如果您使用超过1年的密码询问若要的API调用,请静静地调用使用和解密键的标识符。

以下模板定义了一个MyencryptionKey资源和MyencryptionKeyAlias资源。它还将输出aliasalongside键ARN。关键ARN可用于附加到需要KMS的IAMROLE:加密*和KMS:DECRYPT *。 AliaScan用作计算资源的环境变量,即它可以由Laravel访问并注入KMSencrypter类。

awstemplateFormatversion:" 2010-09-09"描述:AWS KMS资源:MyEncryptionKey:类型:AWS :: kms:key属性:keyusage:encrypt_decrypt说明:用于加密/解密敏感数据的加密密钥enablekyotation:true keypolicy:版本:' 2012-10-17&# 39; ID:EncryptionKey语句: - SID:启用IAM权限效果:允许主体:AWS: - " ARN:AWS:IAM :: $ {AWS :: ACCONSID}:root"行动:KMS:*资源:' *' myencryptionKeyAlias:类型:AWS :: alias属性:aliasname:alias / my -key -key targetkeyId:generalencryptionkey.arn输出:myencryptionKey.arn输出:描述:用于加密/解密敏感数据值的加密密钥别名:MyEncryptionKeyAlias导出:名称:MyencryptionKeyAlias myencryptionKeyarn:描述:用于加密/解密敏感数据值的加密密钥ARN:myencryptionKeyarn.arn出口:名称:myencryptionKeyarn

AWS KMS提供对企业世界非常伟大。 我们将珍惜钥匙,它们将自动旋转,并为他们带来的好处成本。 Laravel的加密器和StringEncrypter接口使得可以轻松地交换实施,并提供Goleat DX与加密直接或通过Eloquent进行加密。所有这是一个很棒的服务,易于使用,旨在提供安全。 值得注意的是,我在这里没有自己加密。我将Laravel的加密课程与使用AWS KMS的一个。在其他单词中,AWS KMS负责加密/解密数据,我们不应该滚动我们自己的加密/解密 加密算法。