这种面向密钥的访问保护模式是已知的惯用语吗?
Posted
技术标签:
【中文标题】这种面向密钥的访问保护模式是已知的惯用语吗?【英文标题】:Is this key-oriented access-protection pattern a known idiom? 【发布时间】:2011-03-14 07:07:34 【问题描述】:Matthieu M. 在this answer 中提出了一种访问保护模式,我以前见过,但从未有意识地考虑过这种模式:
class SomeKey
friend class Foo;
SomeKey()
// possibly make it non-copyable too
;
class Bar
public:
void protectedMethod(SomeKey);
;
这里只有key类的friend
可以访问protectedMethod()
:
class Foo
void do_stuff(Bar& b)
b.protectedMethod(SomeKey()); // fine, Foo is friend of SomeKey
;
class Baz
void do_stuff(Bar& b)
b.protectedMethod(SomeKey()); // error, SomeKey::SomeKey() is private
;
与将Foo
设置为friend
或Bar
相比,它允许更细粒度的访问控制,并避免更复杂的代理模式。
有谁知道这种方法是否已经有了名字,即,是一种已知的模式吗?
【问题讨论】:
可能是一个展示您将如何实际使用这些类的想法。 @Neil:对,这可能并不明显。 使密钥不可复制可能很有用,除非您希望Foo
能够委派对其他类的访问(当然,委派可能很有用,具体取决于具体情况)。跨度>
问:可以用下面的 hack 打败它吗? char* some_junk_object=new char[...]; SomeKey* p=(SomeKey*)(some_junk_object); b.protectedMethod(*p);如果你所做的只是依赖类型系统,那么颠覆是微不足道的。 (我见过类似的密钥系统以类似的方式严重失败。)
@Owen:如果 copy-ctor 是可访问的,是的 - 但同样没有办法保护 C++ 中的所有内容,总有一些 hack 围绕它。我们希望防止错误,而不是故意滥用。如果我们不希望委托并将 copy-ctor 设为非公开,那么您的 hack 将行不通。
【参考方案1】:
感谢your other question,现在看来这种模式被称为“密码”模式。
在 C++11 中,它变得更加简洁,因为不是调用
b.protectedMethod(SomeKey());
你可以打电话:
b.protectedMethod();
【讨论】:
不确定,但如果没有 c++11,则可以选择提供SomeKey
构造函数,例如。一个int
以允许更短的b.protectedMethod(0);
只是一个细节:速记版本foo.bar()
不适用于构造函数,例如Foo foo()
因为它是模棱两可的 - 编译器不知道正在调用哪个构造函数,它可能是一个复制构造函数。或者至少这是一个对我来说似乎合理的解释,如果我错了,请纠正我。
谁能详细说明 b.protectedMethod() 中的 是什么意思;【参考方案2】:
似乎这个成语就像另一个 SO 问题 here 中提到的那样。它被称为 Attorney-Client 成语,并在there 中进行了更详细的描述。
【讨论】:
我已经链接到该问题的另一个答案,并且上面的模式不涉及通过另一个类进行代理。没有我们需要调用的 "attorney"(无论如何它们都很昂贵),而是我们只需传递一个 key 即可获得访问权限。 @Georg:在什么真正意义上,律师所说的昂贵?如果它们是无状态的、仅转发参数的静态内联,将如何引入任何大小或时间损失? @jeff:关于费用的观点是关于小时费率的双关语;)不过,在律师案件中必须手动转发 - 你必须写更多。 @Georg:对不起,把双关语读作通话费用的双关语,而不是定义方法。我大体上同意,但我确实在另一个问题的线程中对实际运行时费用发表了评论。【参考方案3】:像我这样无聊的人会做下面的代码:
int FraudKey=0;
b.protectedMethod(reinterpret_cast<SomeKey&>(FraudKey));
【讨论】:
这在 C++ 中并不令人惊讶——这并不是为了防止恶意意图。 也许将SomeKey
设为Bar
的内部私有可以防止此类用途 - 或至少将其限制为Bar
类。但是,它需要始终使用protectedMethod()
。
您调用了未定义的行为。该错误存在于您的代码中,作为函数的调用者,因为您使用reinterpret_cast
以不同于其实际类型的类型访问对象。由于未定义的行为,荒谬随之而来。
这就是为什么 SomeKey
复制 ctor 也必须是私有的。这确保了它不会编译失败,而有效的使用会成功。【参考方案4】:
它非常接近这个:
http://minorfs.wordpress.com/2013/01/18/raiicap-pattern-injected-singleton-alternative-for-c/
基本上,如果您认为对设计良好的类的对象的引用可以提供 访问控制您需要实现任何真正有意义的访问控制策略,将此模式应用于构造函数以外的任何东西似乎没有那么大的意义。
因此,正如文章所述,如果您将此键与那些构造函数一起使用 访问控制可能是有意义的,代表恐慌资源的重要部分的对象,在 C++ 中通常将被实现为 RAII 对象,而不是名称 RAIICap 或 RAII-Capability 确实有意义。
http://www.eros-os.org/essays/capintro.html
或者,您可以使用更通用的名称来引用它,例如构造权限。
文章中的实现有点过于以 main 为中心,即 main 需要创建所有的权限密钥。您可以通过为密钥本身添加一个额外的公共构造函数来扩展它并使其更加灵活:
template <typename T>
class construct_authority
public:
construct_authority(construct_authority<void> const&)
friend int main(int,char **);
private:
construct_authority()
;
这样 main 可以将密钥创建委托给程序的其他部分。
我个人认为 RAIICap 名称非常适合这种模式的有用部分。
前段时间我提出可以将上面这个简单的模板添加到标准库中。
https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/p_v-aYIvO1E
不幸的是,可以有一个主指纹构成计算根的想法存在问题,所以这样的东西显然不能在标准库中占有一席之地。话虽如此,至少对于与 RAII 类的构造函数一起使用,这种模式似乎非常有用。
【讨论】:
以上是关于这种面向密钥的访问保护模式是已知的惯用语吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何保护 Azure Key Vault 中的 blob 存储访问密钥