ASP.Net 验证区域性名称

发布于 2024-07-12 22:25:04 字数 617 浏览 7 评论 0原文

我们有一个利用 asp.net 2.0 文化的多语言网站。 当前区域性是通过重写为查询字符串的 url 设置的。 (~/es/blah.aspx 是 ~/blah.aspx 的西班牙语版本 - 重写为 ~/blah.aspx?lang=es)

测试区域性的代码如下:

    System.Globalization.CultureInfo ci;
    try
    {
        ci = new System.Globalization.CultureInfo(Request.QueryString["lang"] ?? string.Empty);
    }
    catch
    {
        ci = new System.Globalization.CultureInfo(string.Empty);
    }

如果没有设置区域性,则默认英语,127。当存在文化时,该页面上的所有链接都会在前面加上正确的文化名称。

蜘蛛以某种方式获取了一些 ~/www.test.com/blah.aspx 形式的链接,并用 www.test.com 的文化来攻击我们的网站,并淹没了我们的错误记录。

除了捕获异常之外,还有什么方法可以测试区域性名称是否有效?

We have a multilingual site that utilizes asp.net 2.0 cultures. The current culture is set through the url rewritten as a query string. (~/es/blah.aspx is the spanish version of ~/blah.aspx - rewritten as ~/blah.aspx?lang=es)

The code that tests the culture is as follows:

    System.Globalization.CultureInfo ci;
    try
    {
        ci = new System.Globalization.CultureInfo(Request.QueryString["lang"] ?? string.Empty);
    }
    catch
    {
        ci = new System.Globalization.CultureInfo(string.Empty);
    }

If there is no culture set, it defaults to english, 127. When there is a culture, all links on that page are then pre-pended with the correct culture name.

Some how or another a spider got a hold of a few links in the form of ~/www.test.com/blah.aspx and is hammering our site with a culture of www.test.com which and flooding our error logging.

Is there any way to test whether a culture name is valid besides catching an exception?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

小忆控 2024-07-19 22:25:04

我想我可以快速测量这个,所以创建了一个快速控制台应用程序。

它基本上使用所有 3 种方法(构造函数、LINQ 和 foreach)在循环中 10000 次从字符串中获取 CultureInfo。 为了简洁起见,我删除了秒表和控制台输出。

string culture = "en-GB";
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
for (int i = 0; i < 10000; i++)
{
    try
    {
        CultureInfo c = new CultureInfo(culture);
    }
    catch
    {
    }
}
for (int i = 0; i < 10000; i++)
{
    CultureInfo c = cultures.FirstOrDefault((x) => x.Name == culture);
}
for (int i = 0; i < 10000; i++)
{
    foreach (CultureInfo c in cultures)
    {
        if (c.Name == culture)
            break;
    }
}

结果如下...

Try Catch: 00:00:00.0023860
LINQ: 00:00:00.0542459
ForEach: 00:00:00.0238937

如果删除cultures 变量并在每次迭代时调用它,则 LINQ 和 ForEach 循环大约需要 2.5 秒。

因此,如果您希望获得大量有效输入而仅获得奇数无效输入,那么使用构造函数是有利的。 但是,如果您更改输入从 en-GBTEST 的值,那么情况就会发生巨大变化。

Invalid Culture Try Catch: 00:00:39.7163513
Invalid Culture LINQ: 00:00:00.0791752
Invalid Culture ForEach: 00:00:00.0291480

显然我的测试应用程序不是现实世界的场景,但由于 OP 说这是根据每个请求调用的,我可以想象在大型 Web 应用程序中此代码可能会被多次调用。 它可能是拒绝或服务向量,通过向 Web 服务器发送垃圾邮件,这些请求都具有无效的区域性参数,从而占用所有 CPU。

I thought I'd have a quick go at measuring this so knocked up a quick console application.

It basically uses all 3 methods (constructor, LINQ and foreach) to get a CultureInfo from a string 10000 times in a loop. I removed the stopwatch and console output for brevity.

string culture = "en-GB";
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
for (int i = 0; i < 10000; i++)
{
    try
    {
        CultureInfo c = new CultureInfo(culture);
    }
    catch
    {
    }
}
for (int i = 0; i < 10000; i++)
{
    CultureInfo c = cultures.FirstOrDefault((x) => x.Name == culture);
}
for (int i = 0; i < 10000; i++)
{
    foreach (CultureInfo c in cultures)
    {
        if (c.Name == culture)
            break;
    }
}

The results are as follows...

Try Catch: 00:00:00.0023860
LINQ: 00:00:00.0542459
ForEach: 00:00:00.0238937

If you remove the cultures variable and call it each iteration then the LINQ and ForEach loops take about 2.5 seconds.

So, using the constructor is favourable if you expect to get lots of valid inputs and only the odd invalid one. But if you change the value if the input from en-GB to TEST then things change massively.

Invalid Culture Try Catch: 00:00:39.7163513
Invalid Culture LINQ: 00:00:00.0791752
Invalid Culture ForEach: 00:00:00.0291480

Obviously my test application isn't a real world scenario but since the OP said this is called on a per request basis I can imagine that in a large web application this code could get called a lot. It's possibly a denial or service vector, take up all the CPU by spamming the web server with requests that all have an invalid culture parameter.

肥爪爪 2024-07-19 22:25:04

与已经声明的答案几乎相同,只是使用更紧凑的 linq 表达式:

private static bool IsValidCultureInfoName(string name)
{
    return 
        CultureInfo
        .GetCultures(CultureTypes.SpecificCultures)
        .Any(c => c.Name == name);
}

Pretty much the same answer as already stated only with a more compact linq expression:

private static bool IsValidCultureInfoName(string name)
{
    return 
        CultureInfo
        .GetCultures(CultureTypes.SpecificCultures)
        .Any(c => c.Name == name);
}
物价感观 2024-07-19 22:25:04

您不必使用 LINQ:

private static bool IsValidCultureName(string cultureName)
{
    CultureInfo[] cultures =
        CultureInfo.GetCultures(CultureTypes.SpecificCultures);
    foreach (CultureInfo culture in cultures)
    {
        if (culture.Name == cultureName)
            return true;
    }

    return false;
}

这可能相当昂贵,但可能仍然比处理非常昂贵的异常便宜 - 不过,在相信我的话之前先衡量一下差异。

我认为定义的区域性列表不会在 .NET 版本之间发生变化,因此您应该在启动时获取该列表并将其缓存在某处。

You don't have to use LINQ:

private static bool IsValidCultureName(string cultureName)
{
    CultureInfo[] cultures =
        CultureInfo.GetCultures(CultureTypes.SpecificCultures);
    foreach (CultureInfo culture in cultures)
    {
        if (culture.Name == cultureName)
            return true;
    }

    return false;
}

This could be quite expensive, but possibly still cheaper than dealing with exceptions, which are quite expensive -- measure the difference before taking my word for it, though.

I don't think that the list of defined cultures will change between .NET releases, so you should probably get the list at startup and cache it somewhere.

野稚 2024-07-19 22:25:04

这个网站有一个使用 LINQ 的示例:

CultureInfo[] cultures = System.Globalization.CultureInfo.GetCultures
                         (CultureTypes.SpecificCultures);

var selectCulture = from p in cultures
                    where p.Name == value
                    select p;

if (selectCulture.Count() == 1)
{
    // your culture is good
}

看起来有点沉重,尽管。 我可能会坚持使用你所拥有的。

This site has an example using LINQ:

CultureInfo[] cultures = System.Globalization.CultureInfo.GetCultures
                         (CultureTypes.SpecificCultures);

var selectCulture = from p in cultures
                    where p.Name == value
                    select p;

if (selectCulture.Count() == 1)
{
    // your culture is good
}

It seems a bit heavy, though. I'd probably stick with what you have.

情徒 2024-07-19 22:25:04

这就是我最终为我的动作过滤器所做的事情。
我们只检查语言,而不检查区域设置。

public class HttpInternationalizationAttribute : ActionFilterAttribute
{
    private static readonly HashSet<string> Langs = new HashSet<string>(CultureInfo.GetCultures(CultureTypes.NeutralCultures)
                                                                           .Select(x => x.TwoLetterISOLanguageName.ToUpper()));

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var language = (string)actionContext.ControllerContext.RouteData.Values["language"];

        if (!string.IsNullOrEmpty(language) && Langs.Contains(language.ToUpper()))
        {
            Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(language);
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language);
        }
    }
}

使用哈希集,这将在 O(1) 中运行。

干杯!

Here's what I ended up doing for my Action Filter.
We are only checking for the language, not the locale.

public class HttpInternationalizationAttribute : ActionFilterAttribute
{
    private static readonly HashSet<string> Langs = new HashSet<string>(CultureInfo.GetCultures(CultureTypes.NeutralCultures)
                                                                           .Select(x => x.TwoLetterISOLanguageName.ToUpper()));

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var language = (string)actionContext.ControllerContext.RouteData.Values["language"];

        if (!string.IsNullOrEmpty(language) && Langs.Contains(language.ToUpper()))
        {
            Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(language);
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language);
        }
    }
}

Using a hashset, this will run in O(1).

Cheers !

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文