使用正则表达式在C#中替换连接字符串中的密码。

18

我想在C#中创建一个正则表达式,以替换连接字符串的密码,从而在页面上显示时不会显示密码。连接字符串中的密码可能会以“PWD=password;”形式出现。

到目前为止,我的代码如下:

Regex.Replace(connStr, "PWD=.*;", "PWD=********");

这样可以找到模式的开头,但问题是通配符 (.*) 也包含了 ;,因此模式永远不会终止并且余下的字符串也被替换掉了。如何在正则表达式中表示除了 ; 之外的所有内容?

谢谢。


4
好的,我会尽力进行翻译并保持原意不变。需要翻译的内容是:“Just curious - I'm sure you have a good reason - but why would you ever show even a partial connection string on your web page?” - David
这是一个管理员 Web 应用程序。管理员可以通过应用程序修改连接字符串,但我不希望他们在列表页面上看到密码。 - Paul
5个回答

29
你不需要使用正则表达式 - .NET内置了SqlConnectionStringBuilder类,可以用它来从连接字符串中获取值并更改它们。
示例代码:
string conString = "Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;";
var builder = new SqlConnectionStringBuilder(conString);

builder.Password = "********";

Console.WriteLine(builder.ToString());

我不熟悉Oracle,所以无法确定。但我刚刚谷歌了一下,并找到了OracleConnectionStringBuilder,看起来像是你要找的东西。尽管如此,它已经被弃用并将在未来被删除... Microsoft建议在未来使用第三方提供程序 - Christian Specht
谢谢。如果我记得这个项目(已经有一段时间了),连接字符串可以是任何DMBS,而不仅仅是MSSQL。但还是谢谢你的提示。很好知道这一点。 - Paul
谁说它已经过时了?在我手上的最新的12c ODP.NET中似乎仍然存在。 - Allen
“已弃用”意味着“将在某个时候被移除”。我不记得我6年前发布的MSDN链接中的确切措辞,但现在它重定向到learn.microsoft.com,在那里它说:“此类型已弃用,并将在未来版本的.NET Framework中被删除。有关更多信息,请参见Oracle和ADO.NET。” - Christian Specht
哦,我评论中的第二个链接直接跳转到“Oracle and ADO.NET”页面。 - Christian Specht

24

您可以使用非贪婪量词:

PWD=.*?;

或者排除 ;

PWD=[^;]*;

9
如果这是最后一个项目,且后面没有分号,建议使用以下代码:PWD=([^;]*)(?:$|;)。请注意,翻译过程中不会添加解释或其他信息。 - Dracorat
6
@Paul:这不是不区分大小写。传递 RegexOptions.IgnoreCase 是不区分大小写的 :) - Ry-
@minitech:太酷了!我甚至不知道那是一个选项。这周刚开始学C#。;) - Paul
另外,正如在另一个答案中提到的那样,它可能会出现为PASSWORD而不是PWD,请确保考虑到两者。 - msulis
1
我使用了这个变量 $"({key})=([^;])(?:$|;)",这样我就可以将连接字符串关键字传递给正则表达式并进行掩码处理,例如: var keys = new string[] { "PASSWORD", "PWD", "USER ID", "UID", "DATA SOURCE", "DSN" }; foreach (string key in keys) { pat = $"({key})=([^;])(?:$|;)"; } - Allen
显示剩余2条评论

1
这是我正在使用的正则表达式。
(?<=Password=).+?(?=(;|'|"|$))

使用正向后查找以查找密码的开头,使用正向前查找以查找密码的结尾,并使用非贪婪匹配表达式。在不同情况下,“检测令牌”(Password =;'“$)可能会有所不同。

测试用例:https://regex101.com/

C#实现

using System.Text.RegularExpressions;
private static Regex _regex = new Regex("(?<=Password=).+?(?=(;|'|\"|$))");
//...
var decryptPwdMatch = _regex.Match("some connectionstring for example");
//...


0
很多问题与建议的解决方案有关。这不是纯正则表达式,但处理大小写、空格和可选的尾随分隔符(, 或 ;)。
public static class StringExtensions
{
    public static string MaskField(this string str, string field, string mask = "***")
    {
        var separators = ",;";
        var sb = new StringBuilder();

        foreach (var keyValue in Regex.Split(str, $"(?<=[{separators}])"))
        {
            var temp = keyValue;
            var index = keyValue.IndexOf("=");
            if (index > 0)
            {
                var key = keyValue.Substring(0, index);
                if (string.Compare(key.Trim(), field.Trim(), true) == 0)
                {
                    var end = separators.Contains(keyValue.Last()) ? keyValue.Last().ToString() : "";
                    temp = key + "=" + mask + end;
                }
            }

            sb.Append(temp);
        }

        return sb.ToString();
    }
}

0
我们遇到了这个问题,同事想出了以下的正则表达式:
"(?i)(?:^|.*;)pwd=(\".*\"|.*?)(?:;|$)+?"

或者

"(?i)(?:^|.*;)password=(\".*\"|.*?)(?:;|$)+?"

如果它里面有密码而不是pwd。

密码与以下代码匹配:

            var regex = new Regex(mask);
            var password = string.Empty;
            var match = regex.Match(connectionString);
            if (match.Success && match.Groups.Count > 1)
            {
                password = match.Groups[1].Value;
            }

小心,如果密码在引号中并且也有其他内容也在引号中,.* 将匹配尽可能多的字符。应该将其改为 .*? 才行。另外,(?:^|.*;) 也可以简写为 (?<=^|;) —— 更有效率。 - Ry-
你可以使用一个神奇的正则表达式 (pwd=|password=)!但最好的选择是使用下面提到的 ConnectionStringBuilder... - Allen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接