如何保护存储在 web.config 中的密码?
Posted
技术标签:
【中文标题】如何保护存储在 web.config 中的密码?【英文标题】:How can I secure passwords stored inside web.config? 【发布时间】:2014-01-03 16:37:54 【问题描述】:我在 web.config 文件中添加了以下设置,以启动对外部系统的 API 调用。所以我将 API URL + 用户名 + 密码存储如下:-
<appSettings>
<add key="ApiURL" value="https://...../servlets/AssetServlet" />
<add key="ApiUserName" value="tmsservice" />
<add key="ApiPassword" value="test2test2" />
然后在我的操作方法中,我将在构建 Web 客户端时引用这些值,如下所示:-
public ActionResult Create(RackJoin rj, FormCollection formValues)
XmlDocument doc = new XmlDocument();
using (var client = new WebClient())
var query = HttpUtility.ParseQueryString(string.Empty);
foreach (string key in formValues)
query[key] = this.Request.Form[key];
query["username"] = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiUserName"];
query["password"] = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiPassword"];
string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
但在这里我将公开用户名和密码,并且这些可以被用户捕获,所以我的问题是如何保护 API 用户名和密码?
【问题讨论】:
此链接可能有帮助:infoq.com/articles/Secure-web.config Keeping sensitive information (username & password) in web.config?的可能重复 有关现代建议,请参阅 SCOTT HANSELMAN 的帖子Best practices for private config data and connection strings in configuration in ASP.NET and Azure 【参考方案1】:您可以encrypt the web.config with aspnet_regiis。这是为了阻止有权访问您服务器的人读取敏感信息。
顺便说一句,我会将您的配置设置放在一个类中,然后可以将其注入您的控制器 - 这将使单元测试更容易。
【讨论】:
但我担心的是系统用户将能够捕获这些敏感数据,而不是用户如何访问服务器。所以你的意思是 web.config 数据默认是安全的? 默认情况下是安全的 - IIS 将阻止 Web 用户查看它。但是,您可能有一个显示部分 web.config 的网页,或者您可能将它托管在需要加密敏感信息的地方。 不,我不会在任何网页上显示这些数据。但我仍然需要使用 https。这样系统用户将无法使用安装在浏览器中的插件(例如 firegug、fiddler 工具)来捕获 web.config 数据。是这样吗? 他们将无法捕获 web.config。 那么,如果有人入侵服务器并导航到 web.config 并在记事本中右键单击编辑,该怎么办。现在呢?【参考方案2】:通常,web.config 是一个安全文件,IIS 不提供它,因此它不会暴露给向 Web 服务器发出请求的用户。 Web 服务器只提供特定类型的文件,而 web.config 肯定不是其中之一。
您经常将包含密码的数据库连接字符串保存在其中。现在想象一个 web.config 不安全的场景。您对您的应用程序造成了重大安全威胁。
因此,特别是只要你的项目不是太大,你不应该担心它。
然而,您可能有更好的方法,但创建一个名为“资源”的项目并在其中保存所有关键信息,例如设置、常量、枚举等。这将是一种巧妙而有条理的方法。
如果您通过网络传递用户名/密码(例如在安全 API 调用的情况下),您可能希望使用 https 来确保正在传输的信息是加密的,但这与web.config 文件的安全性。
【讨论】:
web.config 安全性与 https 无关。如果您通过有线发送/接收数据,那么这就是 https 发挥作用的地方。如果您仅在服务器上使用 web.config 上的信息,则无需执行任何操作,一切顺利。我在上面看到的是,您实际上是通过线路发送信息,这确实需要 http,但这与 web.config 安全性无关。您可以从类属性中获取该信息。所以你说的是两个完全不同的领域。 我不同意“您不应该担心[密码安全]”的说法。我经常担心 web.config 中的明文用户名和密码。我在我们的部署脚本中添加了一个步骤来使用 aspnet_regiis 加密生产 web.config。仅仅因为 IIS 不提供 web.config 服务并不意味着有人不会以某种方式破解您的服务器,而只是使用 System.IO 读取文件并显示它。 IMO 这不应该是公认的答案,因为它建议不要关心安全性。 每当我们进行源代码审查时,我都会将任何存储在纯文本文件中的凭据标记为安全风险。 多么可怕的答案 - 难怪有这么多不安全的 IIS 和 ASP.NET 应用程序在外面。根据下面的第二个答案,正确的答案是将您的秘密存储在 webroot 之外并加密。 这个答案还有另一个问题,那就是 web.config 通常存储在源代码控制系统中,因此会复制到各个开发环境中。例如,为了避免传递密码,您可以使用 apsettings 来包含密码文件。生产密码只能存储在生产机器上。【参考方案3】:为什么要使用 Web.config?
与将数据存储在常量、枚举等中相比,将数据存储在 Web.config 中的优点之一是您可以轻松更改不同环境的数据。
保护数据
保护 Web.config 中数据的最佳方法是对其进行加密。而不是像Joe 和user1089766 建议的那样加密配置文件中的整个部分,您可以只加密密码字符串并将其存储在配置中。
检索数据
您可以使用下面的辅助函数来解密密钥。
private const readonly string decryptKey = "";
public string GetFromConfig(string key)
var encryptedText = System.Web.Configuration.WebConfigurationManager.AppSettings[key];
var plainText = Decrypt(encryptedText, decryptKey);
return plainText;
这样,解密密钥将在所有环境通用的项目中。但是您可以轻松更改 web.config 中的数据,而无需重新编译您的应用。
PS:您可以更改每个版本的decryptionKey和对应的数据以提高安全性。
【讨论】:
【参考方案4】:web.config 文件只是文件系统上的一个文件,因此您应该(大多数情况下)像对待任何其他文件一样考虑它的安全性。它不会由 IIS 提供服务(除非您对 IIS 进行坦率的疯狂配置更改 - 易于检查,只需尝试使用浏览器请求它)
使用文件夹权限保护您的网站目录(c:/sites/my-site-here 或其他)是一种很好的做法,仅允许网站应用程序域用户读取文件(以及部署用户,如果需要),方法是使用正常的windows文件权限
因此,如果您对 Web 服务器的安全性有信心,则可能不需要加密。但是,如果您说的是共享主机,或出售网站代码,或者源代码是公开的,那么加密它可能是明智的。不过有点麻烦。
【讨论】:
你能解释更多你的观点吗?所以你的意思是不必在 web.config 中加密敏感数据【参考方案5】:我知道这听起来像是过度工程,但如果可以的话,你真的应该使用秘密管理服务,例如 AWS Secrets Manager 或 Azure Key Vault。
通过将密码存储在 web.config 或 app.config 中,即使是加密形式,也会给自己带来一些问题:
现在您的加密密码将被提交到您的源代码控制,使任何具有读取权限的人都可以访问它们。要正确摆脱它们,您需要执行history rewrite(如果您使用的是git
),这是一个很大的痛苦
虽然您在技术上可以将密码放在机器级配置中,并且在源代码控制之外,但您需要在密码更改时更新所有这些文件
任何知道你加密密码的人现在都可以尝试解密它,使用aspnet_regiis.exe
工具(如果这是你用来加密它的工具),或者如果你rolled your own security,使用你的源代码进行逆向工程,弄清楚它使用什么解密算法和密钥
当您需要更改密码时,您需要更改该文件并重新部署应用程序。
另一方面,当您使用秘密管理服务时,您的源代码中不会存储任何秘密或解密密钥或算法。检索秘密就这么简单:
对于 Azure Key Vault:
var keyVaultUrl = "https://<your-key-vault-name>.vault.azure.net/";
var credential = new DefaultAzureCredential();
var client = new SecretClient(vaultUri: new Uri(keyVaultUrl), credential);
KeyVaultSecret secret = client.GetSecret("<your-secret-name>");
Console.WriteLine($"secret.Name: secret.Value");
对于 AWS Secrets Manager(跳过一些错误处理代码):
var client = new AmazonSecretsManagerClient(accessKeyId, secretAccessKey,
RegionEndpoint.APSoutheast2);
var request = new GetSecretValueRequest
SecretId = secretName
;
GetSecretValueResponse response = null;
response = client.GetSecretValueAsync(request).Result;
与存储本地机密相比,这种方法有很多优势:
您不必在 Prod/Staging/Dev 环境的配置中存储不同的值 - 只需读取适当命名的机密(例如 '[Dev|Prod|Stag]DBPassword` 只有少数人可以访问非常重要的秘密(例如,我不知道,比如Transfer all $$$ from Deus account to all E-Coin wallets everywhere
授权码)
如果有人窃取了您的源代码(心怀不满的员工、意外泄露),您的密码都不会泄露
更改密码很容易 - 您只需使用 can 管理控制台更新密码并重新启动应用程序
我在我的博客上写了几篇文章,展示了如何使用 AWS 和 Azure 设置和阅读机密,如果您需要分步说明和完整源代码,请随时查看:
How to use AWS Secrets Manager to store & read passwords in .Net Core apps How to securely store and retrieve sensitive info in .NET Core apps with Azure Key Vault【讨论】:
要使用这些秘密管理工具,我们必须使用 API_KEY 来获取键值对。那么我们在哪里保存秘密管理的 API_KEY 呢? @MohammadBarbast API_KEY 可以存储在相同类型的保险库中(取决于您的云平台)并由您的构建代理从那里检索,以放置在容器环境变量中。这样它仍然不会出现在源代码之外,您可以在发生违规时快速更改它。 那么,我们必须提供哪些凭据才能获取 API_KEY?【参考方案6】:我必须鼓励您将代码与密钥分开。即使您加密了文件,也有人可以从您的存储库中克隆它,并且当它被加密时,您可能无法再跟踪文件,或者将来可能会访问密钥等等。
另外,正如 Art 所指出的(可能还有线程中的其他人),这使得为 Dev / Test / Prod / 等拥有一组单独的密钥非常容易。如果你加密文件,听起来你要么在所有这些环境中具有相同的加密数据和解密密钥。您不一定有一种简单的方法来改变其中一个而不是其他的。
考虑一下漫长的游戏 - 不仅仅是密码,还应该加载其他配置信息,并且每个环境(API 密钥等)都是唯一的
我们也将这种方法用于开发人员。我不希望每个开发人员都拥有自己的 API 密钥、密码等,因此他们无法访问他们不需要的系统。如果开发笔记本电脑丢失,我可以关闭用户的 API 密钥。我可以轮换 dev / test / prod API 密钥,只需要担心在一个地方进行更改,而不是通知所有用户文件已更新并且他们需要重新克隆。
【讨论】:
以上是关于如何保护存储在 web.config 中的密码?的主要内容,如果未能解决你的问题,请参考以下文章