ASP.Net URL 编码

Posted

技术标签:

【中文标题】ASP.Net URL 编码【英文标题】:ASP.Net URL Encoding 【发布时间】:2010-11-20 07:00:21 【问题描述】:

我正在 ASP.net 中实现 URL 重写,而我的 URL 给我带来了很多问题。

网址是从部门和类别的数据库中生成的。我希望员工能够使用任何适当的特殊字符将项目添加到数据库中,而不会破坏网站。

我在构建 URL 之前对数据进行编码。

有几个问题...

    IIS 在 URL 到达 .net 之前对其进行解码,因此无法正确解析其中包含“/”的任何内容。 ASP.net 被 url 弄糊涂了,使得“~”在某些页面中无用 我从内置测试服务器迁移到我的本地 IIS 服务器(XP 机器),任何包含编码 & (%26) 的 URL 都会给我一个“错误请求”错误。 UrlEncode 保留了一些中断字符不变,例如“.”

我确实有另外两个关于这个主题的相关帖子,当时我只看到上游的小问题而不是大问题。我找到了一些注册表技巧来解决“错误请求”问题,但我将部署到共享托管环境,这使得它变得毫无用处。我也知道这是对一些安全问题的修复,所以我不想在不知道我打开什么蠕虫的情况下绕过它。

与其试图强制 .net 将原始 url 传递给我,或者重写 IIS 设置,我更想首先创建真正安全的 URL。

我会注意到我已经尝试过 AntiXss.URLEncode、HttpUtility.URLEncode、URI.EscapeDataString。我什至尝试过双 URLEncodng 之类的愚蠢操作。是否有一个实用程序可以满足我的需要,或者我真的需要自己动手。我什至正在考虑做一些 Hacky 的事情,比如用不寻常的字符串替换 %。最终结果应该至少是可读的,这是首先使用 URL 重写的重点。

抱歉,这篇文章太长了——我只是想确保我已经包含了所有必要的细节。我似乎找不到任何相关信息,这似乎是一个常见问题 - 所以也许我错过了一些大问题。感谢您的帮助,以及对冗长解释的耐心!


为清楚起见进行编辑:

当我说 url 是从数据库中构建时,我的意思是目录结构是从我的数据库中的部门和类别构建的。

一些示例 URL -

Mystore/Refrigeration/Bar+Fridge.aspx 我的商店/烹饪+设备.aspx Mystore/Kitchen/Cutting+Boards.asxpx

当我使用“Beverage & Bar”或“Pastry/Decorating”之类的部门来构建我的 URL 时,问题就出现了。尽管首先被编码,但这些会导致上述问题。

我的处理程序已经实现并且工作正常,除了特殊字符编码问题。

【问题讨论】:

为了全面披露,这里是我的其他相关帖子-***.com/questions/1274669/…——类似的问题,但我试图强制 .net 给我原始 URL,而不是修复原始 URL关联。 ***.com/questions/1194900/… 在我意识到还有更大的问题之前尝试解决“~”问题。 【参考方案1】:

您应该考虑在您的类别/部门表之外创建一个表,其中每个类别都有一个唯一的 URL。然后,您可以使用特殊的例程来生成 URL。这可以是 SQL 标量函数或 CLR 函数,但它会做的一件事是规范化 Web 的 URL。您可以将“Beverage & Bar”转换为“Beverage-And-Bar”,将“Pastry / Decorating”转换为“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,而无需运行映射功能。

【讨论】:

这绝对是完美的。非常感谢,您为我节省的时间比我承认的要多。【参考方案2】:

我在开始认证请求的 global.asax 文件中实现了 url 重写,因为我有一些安全性。这是我获取原始网址然后进行数据库查找的地方。然后,这会重写 aspx 页面的路径,并且所有参数都通过查询字符串传递。无需编码。

但是,如果您使用 url 来实际更改数据,那么我可以看到您将遇到很大的问题,因为您正在有效地使用 http GET 来更改数据库。这通常被认为是一个坏主意,而不是我做的事情。

我只使用发布请求来进行任何数据库操作。这样可以保持 url 干净,因为所有数据都在页面表单中。

我唯一遇到的问题是将正确的 url 设置为 page.form.action,在大多数情况下是原始 url。

如果是导致问题的类别名称,那么也许您应该将名称限制为仅限字母数字字符,并将空格换成“-”。 IIS 将抛出带有句点“。”的摇摆不定。因为它寻找文件名。

附: IIS 不理解波浪号“~”,这是编译器可以理解的。因此,如果您在锚标记中使用它,它将无法按预期工作,您应该使用应用程序根而不是波浪号。

编辑:

好的,看起来 IIS 存在某些字符问题,例如 . / 和 &。即使您对这些 IIS 进行了 urlencode,它们仍然会尝试实现其自身的含义。 因此考虑删除它们:

Beverage & bar 变成 BeverageBar

糕点/装饰变成 PastryDecorating。

这将使您的网址保持干净,但确实意味着数据库中有一个额外的列,因此您可以根据这个缩短的类别名称检查网址。

【讨论】:

对不起,我应该更清楚 - 我没有对我的 URL 进行任何数据库操作。我的商店分为部门和类别。目录结构不是硬编码的,而是从数据库构建的。各种菜单具有 Mystore/Department 或 Mystore/Department/Category 形式的链接,虽然编码和技术上正确,但在请求甚至返回到我的 httpHandler 之前,它们就被 IIS 破坏了。 这可能是最好的解决方案。我可能只是把事情过度复杂化了。我唯一担心的是我需要能够从 URL 中查找项目,这可能会因不可逆的编码方法而变得复杂。我唯一的另一个想法是使用 Uri.EscapeDataString(b).Replace("%", "_") 我相当肯定这会让我陷入程序员地狱。非常感谢您对此的快速回复和帮助。我正在再次查看我的代码,看看这是否可行。 非常感谢您的帮助。这是我无法接受多个答案而深感沮丧的时刻之一。你为我指明了正确的方向,让我重回正轨……谢谢!!【参考方案3】:

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

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

所以我做了一些手动编码来解决这个问题。这不会完全消除百分比编码,但会大大减少它并防止用户生成无法访问的 url。我的过程从使用Server.URLEncode 函数开始。但这并不能消除 url 中的问题。因为 IIS 正在解码 url,然后将其传递给应用程序,某些字符会以危险的请求异常破坏它。这些字符包括+, &, /, !, *, ., ()。因此,在这些字符加上其他字符上,我想让它们更具可读性,我对更有用的 url 进行了双重编码。由于 url 中允许的字符数量有限,编码也很困难。所以在编码之前,我将所有字母都设为大写,然后用小写进行编码。这使它无法完全解码,但我可以通过将我希望匹配的值设为大写来轻松地在数据库或代码中进行匹配。

嗯,这是我的代码。反馈将不胜感激。哦,是的,这是在 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 扫描拒绝单个智能引号。 发现了很多让 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”)。 查看 web.config 参数,例如 requestFiltering allowDoubleEscaping="true" (***.com/a/1453287/1178314) 和 httpRuntime requestValidationMode="2.0" relaxedUrlToFileSystemMapping="true" requestPathInvalidCharacters=""。在我的用例中,它允许我在 url 中支持更多字符。【参考方案4】:

我猜你正在寻找HttpUtility.UrlEncodeHttpUtility.htmlDecode

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

【讨论】:

感谢您的信息,尽管问题更多是 urlencode/decode 不起作用,因为 asp.net 或 iis 仍然拒绝编码的 url。我想我最终改用了替代方案,但这需要一段时间,所以我有点模糊。

以上是关于ASP.Net URL 编码的主要内容,如果未能解决你的问题,请参考以下文章

encodeURIcomponent编码和ASP.NET之间编码转换

ASP.NET URL 验证

ASP.NET url MAX_PATH 限制

ASP.NET页面的字符编码设置

没有名称的 ASP.NET 网页,例如 ***?

类型:.net;问题:ASP.NET路由;结果:ASP.NET 路由 .NET Framework 4