欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

.NET 证书加密 存储保存 IIS授权

程序员文章站 2022-06-21 16:00:05
最近接到一个任务,加密DotNet项目的配置文件。配置文件里需要加密的地方一共有两块,一个是数据库连接字符串,一个是自定义的所有AppSettings。 一开始接到这个任务我是拒绝的,因为压根不知道怎么加密,印象中的加密方式还停留在MD5。对于啥是对称加密,啥是非对称加密完全不认识。 加密方式 因为 ......

最近接到一个任务,加密dotnet项目的配置文件。配置文件里需要加密的地方一共有两块,一个是数据库连接字符串,一个是自定义的所有appsettings。

一开始接到这个任务我是拒绝的,因为压根不知道怎么加密,印象中的加密方式还停留在md5。对于啥是对称加密,啥是非对称加密完全不认识。

加密方式

因为用的是dotnet所以打开微软doc,希望能找到一点关于dotnet加密的说明文档。

其中.net安全性介绍了一些关于加密的方法。

最常用的加密方式

  • 对称加密

对称加密,使用单个密钥加密和解密数据(通常被用来加密大数据量的东西)。

  • 非对称加密

非对称加密,分为公钥和私钥,利用公钥加密数据,由私钥解密。通常情况下用来保护对称加密的密钥。(在开发过程中发现,用公钥加密一个数据库连接字符串都会由于内容过长而报错)。对于待加密内容比较长的,可以使用分段加密的方式。

数字证书

一开始考虑使用对称方式加密配置文件,但是密钥的存放就是是一个很大的问题,想当然的就打算把密钥放在配置文件里。可是加密的意义何在呢?

所以后来考虑使用非对称方式加密配置文件,利用公钥加密文件,然后利用私钥解密。

存放公钥和私钥的最好工具是数字证书。

通常情况下,数字证书分为两种,一种只有公钥,一种则是有公钥也有私钥。

生成证书

证书其实需要由第三方ca机构来生成的,当然也可以自己生成。

windows平台下微软提供了两种生成方式:

数字证书的存储

看了网上的很多博客,大部分是直接加载本地实体文件,比较高级的是把证书导入到计算机的存储区。

证书存储有两种类型:

  • 本地用户
    • my
    • root
    • trust
    • ca
    • userds
  • 当前用户
    • my
    • root
    • trust
    • ca
    • userds

本地用户除了my以外应该都可以被当前用户继承

导入证书

        //导入文件方法
        private static bool importpfxfile(string filepath, string password = null)
        {
            //证书安装到本地存储,根节点
            x509store store = new x509store(storename.trustedpeople, storelocation.localmachine);

            try
            {
                x509certificate2 certificate = new x509certificate2(filepath, password == null ? "" : password, x509keystorageflags.machinekeyset);

                store.open(openflags.readwrite);

                store.remove(certificate);   //可省略

                store.add(certificate);

                //file.delete(filepath);
                return true;
            }
            catch (system.exception e)
            {
                messagebox.show(e.message);
                return false;
            }
            finally
            {
                store.close();
            }

        }

注意

  • 导入证书的时候注意证书存储标志x509keystorageflags,一般情况下不推荐设置为可导出exportable,所以利用私钥解密的时候,注意私钥的使用方式。

  • 对于证书密码,如果没有直接给null就可以了。

关于给iis授权的问题

运行环境是iis,经测试发现直接运行网站是没有权限获取证书的,需要给iis用户授权才可以。

这个iis用户给我折腾死了。本来以为给 asp.net 授权就可以了,没想到不是的。经过一顿搜索终于明白了,需要授权的是对应程序池的名称。

名称 状态 .net clr 版本 托管管道模式 标识 应用程序
.net v2.0 已启动 v2.0 集成 applicationpoolidentity 0
defaultapppool 已启动 v4.0 集成 applicationpoolidentity 4

比如网站的程序池是defaultapppool,就需要给defaultapppool用户授权。

授权方式一

第一种方式比较简单,利用mmc。

  • 命令行打开mmc
  • 添加证书节点
  • 将其他区的证书托动到个人
  • 右键证书==》所有任务==》管理私钥==》添加对应用户即可
  • 将证书托回到原来分区

授权方式二

第二种方式需要用到两个工具appcmd.exe和winhttpcertcfg.exe。

appcmd.exe是一个iis命令行工具,

appcmd.exe一般会存放在c:\windows\system32\inetsrv\appcmd.exe

这里的使用方式很简单即通过命令获得iis所有程序池信息,执行以下命令

c:\windows\system32\inetsrv\appcmd.exe list apppool

//得到如下结果
apppool "defaultapppool" (mgdversion:v4.0,mgdmode:integrated,state:started)
apppool "classic .net apppool" (mgdversion:v2.0,mgdmode:classic,state:started)
apppool ".net v2.0 classic" (mgdversion:v2.0,mgdmode:classic,state:started)
apppool ".net v2.0" (mgdversion:v2.0,mgdmode:integrated,state:started)
apppool ".net v4.5 classic" (mgdversion:v4.0,mgdmode:classic,state:started)
apppool ".net v4.5" (mgdversion:v4.0,mgdmode:integrated,state:started)

.net 执行此命令

    private dictionary<string, object> mycommand(string filename, string argument)
        {
            try
            {
                processstartinfo startinfo = new processstartinfo(filename)
                {
                    createnowindow = true,
                    useshellexecute = false,
                    redirectstandarderror = true,
                    redirectstandardoutput = true,
                    arguments = argument
                };

                //创建一个进程
                process pc = new process();
                pc.startinfo = startinfo;

                //启动进程
                pc.start();

                //准备读出输出流和错误流
                list<string> listoutput = new list<string>();
                list<string> listerror = new list<string>();
                pc.beginoutputreadline();
                pc.beginerrorreadline();

                pc.outputdatareceived += (ss, ee) =>
                {
                    listoutput.add(ee.data);
                };

                pc.errordatareceived += (ss, ee) =>
                {
                    listerror.add(ee.data);
                };
                //等待退出
                pc.waitforexit();

                //关闭进程
                pc.close();
                dictionary<string, object> dic = new dictionary<string, object>();
                dic.add("output", listoutput);
                dic.add("error", listerror);
                return dic;
            }
            catch (exception e)
            {
                throw e;
            }
        }

通过解析listoutput可以得到程序池名称。

接下来需要用到证书配置工具winhttpcertcfg.exe 详细文档

利用如下命令即可完成授权

winhttpcertcfg -g -c local_machine\my -s mycertificate -a testuser

//local_machine\my:用户\存储区
//mycertificate:证书名
//testuser:授权用户名,即listoutput得到的程序池名称

注意

如果利用appcmd得到程序池名称后执行授权命令,报如下错

error: no account information was found.

这说明程序池并非活跃状态,访问一下对应网站即可。