【问题标题】:Could a security breach happen through Reflection?可以通过反射发生安全漏洞吗?
【发布时间】:2013-07-26 16:32:42
【问题描述】:

假设您在 C# 中有一个函数,它允许您像这样打印出模型的属性:

public void Export<T>(List<T> list)
{    
    // get properties of Model
    Type modelType = typeof(T);
    var modelInstance = Activator.CreateInstance(modelType);
    PropertyInfo[] properties = modelInstance.GetType().GetProperties();

    foreach (var property in properties)
    {
        if (property.CanRead)
            PRINTOUT(property.Name);
    }

    foreach (var entity in list)
    {
        foreach (var property in properties)
        {
            if (property.CanRead)
                PRINTOUT(property.GetValue(entity, null));
        }
    }
}

现在,这个函数在一个控制器中,所以,正如我所读到的,它是一个公开的 HTTP 端点!恶意用户是否可以向PRINTOUT 他不应该看到的属性提问?

为了避免这种情况,我想从另一个控制器调用这个函数,它传入一个非常特定的类型。

例如,控制器Customers 中的PrintoutCustomers 调用该函数,而控制器Products(使用PrintoutProducts 操作)可以调用相同的确切函数,但传入产品列表(而不是客户)。

然后,用户将拥有一个可公开访问的 HTTP 端点的具体列表,其中没有一个会允许他做任何有害的事情。

我希望该功能在我的所有控制器之间私有共享:这可能吗?我可以这样做吗?还是我真的必须在我需要的任何地方复制粘贴相同的方法(并且浪费我的时间尝试使用 typeof 和反射使其通用)?

【问题讨论】:

  • 这样做没有意义:var modelInstance = Activator.CreateInstance(modelType); 你已经有了Type modelType = typeof(T); 的类型,所以就这样做modelType.GetProperties();
  • 我已经尝试过,但这给出了 2 个不同的结果!如果我不实例化该类,由于奇怪的原因,属性是不同的。如果我不实例化,我会得到一堆我一生中从未写过的东西:如果我实例化,我会看到我在类中指定的属性。
  • @Saturnix:真的不应该这样。一定有其他事情发生。
  • 那么我认为这将成为另一个问题的对象,因为它也困扰着我......我发誓这就是我所看到的:getproperties of type = crap。获取实例的属性 = 正确。
  • @Saturnix:很可能,您所做的是以下内容:Type modelType = typeof(T); var properties = modelType.GetType().GetProperties();。注意GetType?不对,modelType 已经是一个类型了。

标签: c# security system.reflection


【解决方案1】:

你为什么要把这个方法放在控制器中?它属于静态助手类或类似的东西。如果你想花哨的话,你甚至可以把它变成一个扩展方法。

public static class OutputExtensions
{
    public static void Export<T>(this List<T> list)
    {
        // get properties of Model
        PropertyInfo[] properties = typeof(T).GetProperties();

        foreach (var property in properties)
        {
            if (property.CanRead)
                PRINTOUT(property.Name);
        }

        foreach (var entity in list)
        {
            foreach (var property in properties)
            {
                if (property.CanRead)
                    PRINTOUT(property.GetValue(entity, null));
            }
        }
    }
}

(此版本还包含 Trevor Pilley 在他的评论中建议的修复)

你可以在每个控制器中这样使用它:

listOfModels.Export();

【讨论】:

  • 我的错,我真的很讨厌在 SO 中格式化代码,因为我不能使用 TAB。非常好的答案!将尝试并标记它是否有效。谢谢!
  • @Saturnix 您可以随时选择代码并单击工具栏中的{ }。这将为您添加 4 个空格:)
  • @ColeJohnson:他这样做了,否则它根本不会被突出显示为代码。问题是代码的不同级别没有正确缩进。
  • @ColeJohnson:是的...所以真的应该在其编辑文本框中提供 ReSharper ;-)
  • 当我这么说的时候,我正处于元精神之中。我就知道你在开玩笑。那好吧。是时候删除过时的 cmets。
【解决方案2】:

在这种情况下,我认为香农的格言适用:

敌人知道系统。

这通常在加密算法的上下文中被引用,但它也适用于这里。是的,这种方法为恶意用户提供了他们可能不知道的内容列表,但理论上,他们也可以查询您的服务器以获取所有可能的单词组合,然后查看哪些有效;这也会给他们一个开放端点的列表。

当你离开你的房子时,你不会在你的门上伪装 - 你会锁上它。同样的原则在这里也适用:如果有一些用户不应该做的事情,请确保您的身份验证和授权代码有效,并适当地拒绝访问您想要阻止他们进入的任何内容。简单地隐藏东西被称为通过默默无闻的安全,简而言之,它不起作用。

当您制作可以连接到网络的软件时,隐藏某些内容以减少攻击者的注意力是可以(通常也是一个好主意),但即便如此,您也应该假设在某些时候恶意用户 会发现它们的存在,你应该保护它们免受恶意使用。

在您的特定情况下,我会说以下内容:

  • 你可以不用这个特殊功能吗?
  • 您能否以另一种方式减少系统的暴露?
  • 恶意用户可以使用此功能做您不希望他们做的事情吗?

如果其中任何一个的答案是“是”,那么您可能不应该这样做。如果 only 如果 all 他们都是“否”,那么你很好。就个人而言,我认为您忘记了一个简单的规则:如果不需要从 Web 访问它,请不要将它放在控制器中!考虑将此方法移至逻辑层中的内部类,只有您受信任的代码才能访问它。

【讨论】:

  • 通过默默无闻的安全性绝对是我想避免的事情:这就是我的问题的全部意义。如何使该功能对所有控制器可用,但对用户不可用。用户只能通过非常特定的公共控制器调用它,这限制了函数的操作。
  • 把函数本身放在另一个类中,这样你的控制器可以访问它,但用户不能。然后在控制器方法中使用逻辑来将此功能的使用限制为您想要的特定用途。用户不能直接调用该方法;他们必须通过控制器,它拒绝任何你不喜欢的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-12
  • 1970-01-01
  • 2017-11-24
  • 2011-12-17
  • 1970-01-01
  • 1970-01-01
  • 2021-08-19
相关资源
最近更新 更多