当前位置: 移动技术网 > IT编程>开发语言>.net > .NetCore分布式部署中的DataProtection密钥安全性

.NetCore分布式部署中的DataProtection密钥安全性

2019年01月13日  | 移动技术网IT编程  | 我要评论

综漫半神,花魁艺色馆,17岁学霸旷课求婚

在.netcore中默认使用dataprotection来保护数据,例如cooike等。一般情况下dataprotection生成的密钥会被加密后存储,例如默认的文件存储

可以看到使用了windows dpapi加密。

但是如果更改默认设置例如使用的外部存储如redis则此时密钥默认是不加密的

微软说明如下

警告密钥未加密,这个时候如果redis被破解,系统的密钥也就泄漏了。

微软提供了2个接口ixmlencryptor,ixmldecryptor来实现密钥的加密解密,下面使用aes来简单现实,也可以替换为任何加密方式

namespace microsoft.aspnetcore.dataprotection
{
    /// <summary>
    /// extensions for configuring data protection using an <see cref="idataprotectionbuilder"/>.
    /// </summary>
    public static class dataprotectionbuilderextensions
    {
        /// <summary>
        /// configures keys to be encrypted with aes before being persisted to
        /// storage.
        /// </summary>
        /// <param name="builder">the <see cref="idataprotectionbuilder"/>.</param>
        /// use on the local machine, 'false' if the key should only be decryptable by the current
        /// windows user account.</param>
        /// <returns>a reference to the <see cref="idataprotectionbuilder" /> after this operation has completed.</returns>
        public static idataprotectionbuilder protectkeyswithaes(this idataprotectionbuilder builder)
        {
            if (builder == null)
            {
                throw new argumentnullexception(nameof(builder));
            }

            builder.services.addsingleton<iconfigureoptions<keymanagementoptions>>(services =>
            {
                //var loggerfactory = services.getservice<iloggerfactory>() ?? nullloggerfactory.instance;
                return new configureoptions<keymanagementoptions>(options =>
                {
                    options.xmlencryptor = new aesxmlencryptor();
                });
            });

            return builder;
        }
    }
    /// <summary>
    /// an <see cref="ixmlencryptor"/> that encrypts xml elements with a aes encryptor.
    /// </summary>
    sealed class aesxmlencryptor : ixmlencryptor
    {
        /// <summary>
        /// encrypts the specified <see cref="xelement"/> with a null encryptor, i.e.,
        /// by returning the original value of <paramref name="plaintextelement"/> unencrypted.
        /// </summary>
        /// <param name="plaintextelement">the plaintext to echo back.</param>
        /// <returns>
        /// an <see cref="encryptedxmlinfo"/> that contains the null-encrypted value of
        /// <paramref name="plaintextelement"/> along with information about how to
        /// decrypt it.
        /// </returns>
        public encryptedxmlinfo encrypt(xelement plaintextelement)
        {
            if (plaintextelement == null)
            {
                throw new argumentnullexception(nameof(plaintextelement));
            }
            // <encryptedkey>
            //   <!-- this key is encrypted with {provider}. -->
            //   <value>{base64}</value>
            // </encryptedkey>

            var jsonxmlstr =jsonconvert.serializeobject(plaintextelement);
            var encrypteddata = encrypthelper.aesencrypt(jsonxmlstr, "b587be32-0420-4eb1-89c6-01bb999e18fe");
            var newelement = new xelement("encryptedkey",
                new xcomment(" this key is encrypted with aes."),
                new xelement("value",encrypteddata));

            return new encryptedxmlinfo(newelement, typeof(aesxmldecryptor));
        }
    }
    /// <summary>
    /// an <see cref="ixmldecryptor"/> that decrypts xml elements with a aes decryptor.
    /// </summary>
    sealed class aesxmldecryptor : ixmldecryptor
    {
        /// <summary>
        /// decrypts the specified xml element.
        /// </summary>
        /// <param name="encryptedelement">an encrypted xml element.</param>
        /// <returns>the decrypted form of <paramref name="encryptedelement"/>.</returns>
        public xelement decrypt(xelement encryptedelement)
        {
            if (encryptedelement == null)
            {
                throw new argumentnullexception(nameof(encryptedelement));
            }

            // <encryptedkey>
            //   <!-- this key is encrypted with {provider}. -->
            //   <value>{base64}</value>
            // </encryptedkey>
            var encrypteddata=(string)encryptedelement.element("value");
            var jsonxmlstr = encrypthelper.aesdecrypt(encrypteddata, "b587be32-0420-4eb1-89c6-01bb999e18fe");

            // return a clone of the single child node.
            return jsonconvert.deserializeobject<xelement>(jsonxmlstr);
        }
    }
    #region aes
    public class encrypthelper
    {
        static readonly byte[] aes_iv = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef };
        /// <summary>
        /// aes加密算法
        /// </summary>
        /// <param name="encryptstring">加密前字符串</param>
        /// <param name="keytype">秘钥</param>
        /// <returns></returns>
        public static string aesencrypt(string encryptstring, string encryptkey)
        {
            if (string.isnullorwhitespace(encryptstring)) return null;
            if (string.isnullorwhitespace(encryptkey)) return null;
            encryptkey = encryptkey.padright(32, ' ');
            byte[] keybytes = encoding.utf8.getbytes(encryptkey.substring(0, 32));
            using (aescryptoserviceprovider aesalg = new aescryptoserviceprovider())
            {
                aesalg.key = keybytes;
                aesalg.iv = aes_iv;
                icryptotransform encryptor = aesalg.createencryptor(aesalg.key, aesalg.iv);
                using (memorystream msencrypt = new memorystream())
                {
                    using (cryptostream csencrypt = new cryptostream(msencrypt, encryptor, cryptostreammode.write))
                    {
                        using (streamwriter swencrypt = new streamwriter(csencrypt))
                        {
                            swencrypt.write(encryptstring);
                        }
                        byte[] bytes = msencrypt.toarray();
                        return convert.tobase64string(bytes).replace('+', '-').replace('/', '_');
                    }
                }
            }
        }
        /// <summary>
        /// aes解密算法
        /// </summary>
        /// <param name="decryptstring">解密前的字符串</param>
        /// <param name="keytype">秘钥</param>
        /// <returns></returns>
        public static string aesdecrypt(string decryptstring, string decryptkey)
        {
            if (string.isnullorwhitespace(decryptstring)) return null;
            decryptstring = decryptstring.replace('-', '+').replace('_', '/');
            if (string.isnullorwhitespace(decryptkey)) return null;
            decryptkey = decryptkey.padright(32, ' ');
            byte[] keybytes = encoding.utf8.getbytes(decryptkey.substring(0, 32));
            byte[] inputbytes = convert.frombase64string(decryptstring);
            using (aescryptoserviceprovider aesalg = new aescryptoserviceprovider())
            {
                aesalg.key = keybytes;
                aesalg.iv = aes_iv;
                icryptotransform decryptor = aesalg.createdecryptor(aesalg.key, aesalg.iv);
                using (memorystream msencrypt = new memorystream(inputbytes))
                {
                    using (cryptostream csencrypt = new cryptostream(msencrypt, decryptor, cryptostreammode.read))
                    {
                        using (streamreader srencrypt = new streamreader(csencrypt))
                        {
                            return srencrypt.readtoend();
                        }
                    }
                }
            }
        }
    }
    #endregion
}
view code

 

调用也很简单.protectkeyswithaes()即可

  services.adddataprotection().setapplicationname("dataprotection").persistkeystostackexchangeredis(connectionmultiplexer.connect(redisconnection), "dataprotection-keys").protectkeyswithaes();

加密后的密钥如下

注:在生成密钥之前要删除之前的密钥,不然会使用旧密钥而不生成新的密钥直到密钥过期。

 

对于aes所使用密钥也要进行保护,可以使用第三方密钥存储库如azure 密钥保管库,或者也可以使用x509证书来来加密。

 github  https://github.com/saber-wang/dataprotection

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网