ASP.Net URL编码

7
我正在ASP.net中实现URL重写,我的URLs给我带来了一系列问题。
URL是从部门和类别的数据库生成的。我希望员工能够向数据库添加任何适当的特殊字符而不会破坏网站。
我在构造URL之前对数据进行编码。
有几个问题:
1. IIS在到达.net之前解码URL,使得无法正确解析任何包含“/”的内容。 2. ASP.net对URL感到困惑,在某些页面中“~”无用。 3. 我从内置测试服务器迁移到了本地IIS服务器(XP机器),任何包含编码的&(%26)的URL都会给我“Bad Request”错误。 4. UrlEncode会保留某些破坏性字符,例如'。'
我确实在这个主题上有另外两篇相关文章,但当时我只看到了小问题,没有看到上游的大问题。我已经找到了一些注册表技巧来解决“Bad Request”问题,但我将要部署到共享托管环境,这使得它无用。我也知道这是某些安全问题的解决方法,所以我不想绕过它而不知道我打开了什么样的问题。
与其试图强制.net传递原始url,或者覆盖IIS设置,我更愿意首先创建真正安全的URL。
我要注意的是,我已经尝试过AntiXss.URLEncode,HttpUtility.URLEncode,URI.EscapeDataString。我甚至尝试了愚蠢的事情,比如双重URLEncodng。是否有一个能够满足我的需求的实用程序,或者我真的需要自己编写。我甚至考虑做一些hacky的事情,比如用一个不寻常的字符串替换%。最终结果应该至少是可读的,这也是使用URL重写的目的。
抱歉发了这么长的帖子-我只是想确保我包括了所有必要的细节。我似乎找不到任何相关信息,而且它似乎会是一个普遍的问题-所以也许我错过了什么大问题。感谢您的帮助和耐心解释!

为了充分披露,这里是我其他相关帖子的链接:http://stackoverflow.com/questions/1274669/url-encoding-being-lost-before-processing-asp-net -- 相似的问题,但我试图强制 .net 给我原始的 URL 而不是修复原始链接上的编码。http://stackoverflow.com/questions/1194900/asp-net-path-problems-caused-by-encoded-urls 在意识到有更大的问题之前,试图解决“~”问题。 - Kelly Robins
4个回答

5
您应该考虑在类别/部门表之外设置一个表格,为每个类别提供唯一的URL。然后,您可以使用特殊程序生成URL。这可以是SQL标量函数或CLR函数,但其中一件事情是将Web的URL进行规范化。您可以将“饮料和酒吧”转换为“Beverage-And-Bar”,将“糕点/装饰”转换为“Pastry-Decorating”。主要是,该程序需要用其他字符替换所有无效的HTTP URL字符。以下是一个示例:
public static class URL
{
    static readonly Regex feet = new Regex(@"([0-9]\s?)'([^'])", RegexOptions.Compiled);
    static readonly Regex inch1 = new Regex(@"([0-9]\s?)''", RegexOptions.Compiled);
    static readonly Regex inch2 = new Regex(@"([0-9]\s?)""", RegexOptions.Compiled);
    static readonly Regex num = new Regex(@"#([0-9]+)", RegexOptions.Compiled);
    static readonly Regex dollar = new Regex(@"[$]([0-9]+)", RegexOptions.Compiled);
    static readonly Regex percent = new Regex(@"([0-9]+)%", RegexOptions.Compiled);
    static readonly Regex sep = new Regex(@"[\s_/\\+:.]", RegexOptions.Compiled);
    static readonly Regex empty = new Regex(@"[^-A-Za-z0-9]", RegexOptions.Compiled);
    static readonly Regex extra = new Regex(@"[-]+", RegexOptions.Compiled);

    public static string PrepareURL(string str)
    {
        str = str.Trim().ToLower();
        str = str.Replace("&", "and");

        str = feet.Replace(str, "$1-ft-");
        str = inch1.Replace(str, "$1-in-");
        str = inch2.Replace(str, "$1-in-");
        str = num.Replace(str, "num-$1");

        str = dollar.Replace(str, "$1-dollar-");
        str = percent.Replace(str, "$1-percent-");

        str = sep.Replace(str, "-");

        str = empty.Replace(str, string.Empty);
        str = extra.Replace(str, "-");

        str = str.Trim('-');
        return str;
    }
}

您可以将此作为SQL增强功能,或将URL生成作为单独的进程运行。然后,要实现映射,您将直接将整个URL映射到类别ID。从长远来看,这种方法有几个优点。首先,您不必总是生成URL,只需生成一次即可保持静态,无需担心过程更改,然后GoogleBot找不到旧的URL。此外,如果发生碰撞,您可能会注意到潜在的重复类别名称,因为碰撞仅由特殊字符不同。最后,您可以随时从数据库中查看URL,而无需运行映射函数。

1
那真是太完美了。非常感谢,你为我省下了比我愿意承认的更多时间。 - Kelly Robins

2
我在全局.asax文件中实现了一个URL重写,因为我有一些安全性。这是我获取原始URL并进行数据库查找的地方。然后将路径重写为aspx页面,并通过查询字符串传递所有参数。不需要编码。
但是,如果您使用URL实际更改数据,则会遇到巨大的问题,因为您实际上正在使用HTTP GET来更改数据库。通常被认为是一个坏主意,而且不是我做的事情。
我只使用POST请求来进行任何数据库操作。这使得URL保持清洁,因为所有数据都在页面表单中。
我唯一遇到的问题是设置正确的url到page.form.action,大多数情况下是原始url。
如果类别名称引起问题,那么也许你应该将名称限制为仅包含字母数字字符,并将空格替换为“-”。IIS会抛出一个错误,因为它正在寻找文件名。
P.S. IIS不理解波浪符“~”,这是编译器理解的内容。因此,如果您在锚标记中使用它,它将无法按预期工作,您应该使用应用程序根代替波浪符。
编辑: 好吧,看起来有一个问题,即IIS对某些字符(如. /和&)存在问题。即使您对这些字符进行urlencode,IIS仍然会尝试实现自己的含义。 因此,请考虑删除它们,例如: 饮料和酒吧变成BeverageBar 糕点/装饰变成PastryDecorating。 这将使您的URL保持清洁,但意味着数据库中有一个额外的列,以便您可以检查URL与此缩短的类别名称是否匹配。

抱歉,我应该表达得更清楚-我没有对我的URL进行任何数据库操作。我的商店被分成了部门和类别。目录结构不是硬编码的,而是从数据库中建立的。各种菜单具有形式为Mystore/Department或Mystore/Department/Category的链接,虽然已编码并且在技术上正确,但在请求返回到我的httpHandler之前,它们被IIS破坏了。 - Kelly Robins
那可能是最好的解决方案。我可能一直在过度复杂化事情。我的唯一担忧是我需要能够从URL中查找项目,这可能会被不可逆的编码方法所复杂化。我唯一的其他想法是使用Uri.EscapeDataString(b).Replace("%", "_"),但我相当确定这会让我陷入程序员地狱。非常感谢您的快速响应和帮助。我正在重新审视我的代码,看看这是否可行。 - Kelly Robins
非常感谢您的帮助。这是我深感沮丧的时刻之一,因为我无法接受多个答案。您指引了我正确的方向,并让我重新回到了正轨... 谢谢! - Kelly Robins

1

我有完全相同的问题。谢谢你把它写得这么好。这实际上帮助我更好地理解了问题。

不过,我有一些其他考虑因素。我其中一个目标是支持任何字符可能在基于文章标题的URL中出现。此外,我想确保编码的唯一性并实现双向编码/解码过程。

所以我做了一些手动编码来解决这个问题。这不会完全消除百分号编码,但会大大减少它,并防止用户生成无法访问的网址。我的过程是先使用Server.URLEncode函数。但这并不能解决网址中的问题。因为IIS会对网址进行解码,然后将其传递给应用程序,在某些字符上会导致危险的请求异常。这些字符包括+, &, /, !, *, ., ()。所以在这些字符以及其他我想要更可读的字符上,我会进行双重编码以获得更可用的网址。编码也很困难,因为在网址中允许的字符数量有限。因此,在进行编码之前,我将所有字母都转为大写,然后再用小写进行编码。这样可以避免完全可解码,但我可以通过使要匹配的值变成大写,在数据库或代码中轻松进行匹配。
好了,这是我的代码。欢迎提供反馈。哦,对了,这是VB代码,但应该很容易转换到C#。
Dim strReturn As String = Trim(strStringToEncode)
strReturn = Server.UrlEncode(strReturn)

strReturn = strReturn.Replace("-", "dash").Replace("+", "-")

strReturn = strReturn.Replace("%26", "and").
                    Replace("%2f", "or").
                    Replace("!", "excl").
                    Replace("*", "star").
                    Replace("%27", "apos").
                    Replace("(", "lprn").
                    Replace(")", "rprn").
                    Replace("%3b", "semi").
                    Replace("%3a", "coln").
                    Replace("%40", "at").
                    Replace("%3d", "eq").
                    Replace("%2b", "plus").
                    Replace("%24", "dols").
                    Replace("%25", "pct").
                    Replace("%2c", "coma").
                    Replace("%3f", "query").
                    Replace("%23", "hash").
                    Replace("%5b", "lbrk").
                    Replace("%5d", "rbrk").
                    Replace(".", "dot").
                    Replace("%3e", "gt").
                    Replace("%3c", "lt")

Return strReturn

已经发现了一个问题。URL扫描拒绝单个智能引号。 - Nate
发现很多引号会让urlscan出问题。这将有助于解决它。 替换("%e2%80%99", "rsquo")。 替换("%e2%80%98", "lsquo")。 替换("%e2%80%9d", "rdquo")。 替换("%e2%80%9c", "ldquo")。 替换("%e2%80%9b", "lsrquo")。 替换("%e2%80%9f", "ldrquo")。 - Nate
请查看 web.config 参数,例如“requestFiltering allowDoubleEscaping=" true "(https://dev59.com/wnM_5IYBdhLWcg3wQQzw#1453287) 和httpRuntime requestValidationMode="2.0" relaxedUrlToFileSystemMapping="true" requestPathInvalidCharacters=""`。在我的使用场景中,它允许我支持更多的 URL 字符。 - Frédéric

0

我猜你在找的是 HttpUtility.UrlEncodeHttpUtility.HtmlDecode

string url = "http://www.google.com/search?q=" + HttpUtility.UrlEncode("Example");

1
谢谢你提供的信息,不过问题更多在于urlencode / decode无法正常工作,因为asp.net或iis仍然拒绝编码后的URL。我想我最终使用了一个替换方案,但这是一段时间之前的事情,所以我有点模糊。 - Kelly Robins

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