确定绝对URL还是相对URL

67

我有一个字符串中包含相对路径或绝对路径url。首先,我需要知道它是绝对路径还是相对路径。我该如何实现?然后,我想确定url的域名是否在允许列表中。

以下是示例允许列表:

string[] Allowed =
{
   "google.com",
   "yahoo.com",
   "espn.com"
}

我认为一旦我知道它是相对路径还是绝对路径,就很简单了:

if (Url.IsAbsolute)
{
    if (!Url.Contains("://"))
        Url = "http://" + Url;

    return Allowed.Contains(new Uri(Url).Host);
}
else //Is Relative
{
    return true;
}

4
请勿忘记,有些人使用 www 子域名。 - icktoofay
确定一个URL是绝对路径还是相对路径,使用VB实现。 - Michael Freidgeim
3个回答

119
bool IsAbsoluteUrl(string url)
{
    Uri result;
    return Uri.TryCreate(url, UriKind.Absolute, out result);
}

7
你可以使用 Uri.TryCreate 方法来使代码更加简短清晰。 - Ian Henry
4
System.Uri仅当方案(http/https等)存在时才认为它是绝对的,但浏览器(通常是用户代理)会假定协议相对的'//pirate.ru/' URL具有相同的方案。 - yzorg
10
继 @yzorg 的评论后,你可能还应确保 url 值不以 '//' 开头。如果你正在使用它来检查有效的重定向,那么你应该一定要这样做。如果有人知道更好或更可靠的检测协议相对 URL 的方法,我会倾听意见。 - JT.
2
这将从/dir/example-img.jpg返回true。那是相对路径,对吗? - TEK
5
@TEK说:“一个绝对路径,但是一个相对URI。” - Sz.
显示剩余2条评论

44

由于某些原因,一些好的回答被其作者删除:

通过@Chamika Sandamal

Uri.IsWellFormedUriString(url, UriKind.Absolute)

Uri.IsWellFormedUriString(url, UriKind.Relative)

通过@Marcelo Cantos的实现,使用UriParser


1
不幸的是,这会对绝对URI(例如//www.google.com)产生false的结果(您可以重定向到它,浏览器会访问实际域)。这可能会导致严重的安全问题。请查看上面答案中@JT的评论。 - Wiktor Zychla
不幸的是,302 在每个浏览器中都是这样处理的。如果有人想检查他们是否容易受到开放式重定向攻击,并且在谷歌上搜索“如何检查 URL 是否为绝对路径”,并跳转到这里并按照提供的答案进行操作,那么漏洞仍然存在。请注意,此评论并非指出您的答案错误(它并没有错),而是作为对寻找略有不同问题答案的人的警告。我也是其中之一。 - Wiktor Zychla
如果您想防止开放式重定向,可以测试maybeUnsafeUri.Host - Chris Marisic
maybeUnsafeUri.Host 是什么? - Wiktor Zychla
var maybeUnsafeUri = new Uri(externalStringUrl) 然后您可以测试主机以确保它是一个可信的服务器。 - Chris Marisic

3
您可以使用UriBuilder直接实现您想要的功能,它可以处理相对和绝对URI(请参见以下示例)。
同时,@icktoofay也提出了一个好建议:一定要在允许列表中包含子域名(如www.google.com),或者对builder.Host属性进行更多处理以获取实际域名。如果决定进行更多处理,请勿忘记带有复杂顶级域名(如bbc.co.uk)的URL。
using System;
using System.Linq;
using System.Diagnostics;

namespace UriTest
{
    class Program
    {
        static bool IsAllowed(string uri, string[] allowedHosts)
        {
            UriBuilder builder = new UriBuilder(uri);
            return allowedHosts.Contains(builder.Host, StringComparer.OrdinalIgnoreCase);
        }

        static void Main(string[] args)
        {
            string[] allowedHosts =
            {
                "google.com",
                "yahoo.com",
                "espn.com"
            };

            // All true
            Debug.Assert(
                IsAllowed("google.com", allowedHosts) &&
                IsAllowed("google.com/bar", allowedHosts) &&
                IsAllowed("http://google.com/", allowedHosts) &&
                IsAllowed("http://google.com/foo/bar", allowedHosts) &&
                IsAllowed("http://google.com/foo/page.html?bar=baz", allowedHosts)
            );

            // All false
            Debug.Assert(
                !IsAllowed("foo.com", allowedHosts) &&
                !IsAllowed("foo.com/bar", allowedHosts) &&
                !IsAllowed("http://foo.com/", allowedHosts) &&
                !IsAllowed("http://foo.com/foo/bar", allowedHosts) &&
                !IsAllowed("http://foo.com/foo/page.html?bar=baz", allowedHosts)
            );
        }
    }
}

这个能处理相对路径吗?比如 ./page/test.aspx。编辑:我刚测试了一下,它无法处理相对路径。uribuilder有处理相对路径的方法吗? - Mark
@Mark: 不,UriBuilder 没有办法知道在那种情况下你想要什么主机。 它会抛出异常。 我认为任何方法都无法处理这种情况,因为该 URL 是相对于无何物的(或至少未指定)。 - Chris Schmich
@Mark:忽略我上一条评论,我看到你只想在相对情况下返回true;,所以你可以像@Ian建议的那样使用Uri.TryCreate - Chris Schmich
我使用了另一段代码来确定URL是绝对路径还是相对路径,而你的代码则用于包含部分。谢谢。 - Mark

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