怎么能不使用“最终”呢?是一个安全问题吗?

发布于 2024-11-23 16:06:33 字数 735 浏览 1 评论 0原文

来自 O'Reilly 的 Essential ActionScript 3.0 (2007) 第 113 页:

final 方法有助于隐藏类的内部细节。制作一个类或一个 方法final阻止其他程序员扩展类或重写 该方法用于检查类的内部结构。这样的预防 被认为是保护应用程序免遭攻击的方法之一 恶意利用

这是指使用已编译、闭源包的 API 并“恶意利用”来学习有关类设计的内容的用户吗?这真的是个问题吗?

对于更多上下文,这是使用 final 的两个原因中的第二个。在 2007 年版中,它位于第 113 页的“继承”一章中,副标题为“防止类被扩展和方法被重写”。

在 ActionScript 中使用 Final 属性有两个原因:

  • 在某些情况下,最终方法比非最终方法执行得更快。如果你 正在寻求以各种可能的方式提高应用程序的性能,请尝试 使其方法最终确定。但请注意,在未来的 Flash 运行时中,Adobe 期望非最终方法与最终方法一样快地执行。

  • final 方法有助于隐藏类的内部细节。制作一个类或一个 方法final阻止其他程序员扩展类或重写 该方法用于检查类的内部结构。这样的预防 被认为是保护应用程序免遭攻击的方法之一 被恶意利用。

From page 113 of O'Reilly's Essential ActionScript 3.0 (2007):

Methods that are final help hide a class’s internal details. Making a class or a
method final prevents other programmers from extending the class or overriding
the method for the purpose of examining the class’s internal structure. Such prevention
is considered one of the ways to safeguard an application from being
maliciously exploited
.

Does this refer to users of the API of a compiled, closed-source package, and "maliciously exploited" to learning things about the class design? Is this really a problem?

For some more context, it's the second of two reasons to use final. In the 2007 edition, it's on page 113 in the chapter Inheritance under subtitle Preventing Classes from Being Extended and Methods from Being Overridden.

The final attribute is used for two reasons in ActionScript:

  • In some situations, final methods execute faster than non-final methods. If you
    are looking to improve your application’s performance in every possible way, try
    making its methods final. Note, however, that in future Flash runtimes, Adobe
    expects non-final methods to execute as quickly as final methods.

  • Methods that are final help hide a class’s internal details. Making a class or a
    method final prevents other programmers from extending the class or overriding
    the method for the purpose of examining the class’s internal structure. Such prevention
    is considered one of the ways to safeguard an application from being
    maliciously exploited.

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

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

发布评论

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

评论(3

凉薄对峙 2024-11-30 16:06:33

在许多语言中,重写方法是从基类中选择加入的。通常,virtual 关键字允许基类作者选择重写的可能性。

然而,在 AS3 中,重写方法的能力是选择退出的。这就是 final 关键字的作用。它允许基类作者说“这个方法可能不会被重写”。

有一些关于封装的老派想法表明 AS3 这样做会带来安全问题。但这主要是在公共 API 的情况下,您希望隐藏内容但公开功能。

但是,在更现代的时代,我们了解到反汇编和反射将允许恶意开发人员做他/她想做的任何事情,所以今天这不再是一个问题。在我看来,依靠 final 来保证安全是一个拐杖,任何关于它的建议都应该被驳回。安全性需要比这更仔细地考虑。 API 需要进行架构设计,以便开发人员可以执行需要执行的操作,但安全关键信息不应包含在公共 API 中。

这并不是说 final 没有用。 final 告诉从您的类派生的开发人员您从未打算让他们重写该函数。它让你说“请只调用这个函数。不要覆盖。”在我看来,它更像是一种接口或通信机制。

In many languages, overriding methods is opt-in from the base class. Often, it is the virtual keyword that allows base class authors to opt-in for the possibility of overriding.

In AS3, however, the ability to have methods overridden is opt-out. That is what the final keyword does. It allows the base class author to say "this method may not be overridden".

There are some old-school thoughts about encapsulation that would suggest that it is a security problem for AS3 to do it this way. But this is mostly in cases of public APIs in which you want to hide your content but expose the functionality.

But, in more modern times, we have learned that disassembly and reflection will allow a malicious developer to do anything he/she wants anyways, so this is less of an issue today. Relying on final for security is a crutch, in my opinion, and any suggestions of it should be dismissed. Security needs to be thought of more carefully than that. APIs need to be architected such that the implementation lets developers do what then need to do, but security-critical information should not be included in public APIs.

That is not to say that final is not useful. final tells developers that derive from your class that you never intended them to override the function. It lets you say "please just call this function. Don't override." It is more of an interface or a communications mechanism than anything else, IMO.

我不咬妳我踢妳 2024-11-30 16:06:33

Final 关键字不用于这种安全性。它不能替代通常需要的加密解决方案。

在这类讨论中,“安全”通常指的是安全对象模型的概念,也就是说,消费者不能出于类的原始作者的非预期目的而操纵对象模型。

某种程度上,一个构造良好的类将封装其状态,而一个仅具有最终方法的类将不允许使用者覆盖该类的行为并更改状态的封装方式。类可以公开其状态(例如通过公共字段),并且没有final关键字能够保护该状态的完整性。

它更多的是“改变”东西而不是“保护”。最终关键字只是放弃了更改/修改/扩展任何方法的能力。

它不会使您的代码更安全,它比其他任何东西都更能保证线程安全。如果变量被标记为final,则在创建对象时必须为其赋值。创建对象后,不能使该变量引用另一个值。

此行为允许您推断对象的状态,并在多个线程同时访问该对象时做出某些假设。

我不认为进行现场决赛会增加针对恶意攻击的安全性(更有可能针对错误,当然还有线程问题)。安全性的唯一“真实形式”是,如果您有一个最终常量字段,它可能会在编译时内联,因此在运行时更改其值不会产生任何影响。

我在继承的背景下更多地听说过最终和安全性。通过将类设为最终类,您可以防止某人对其进行子类化并触摸或覆盖其受保护的成员,但我再次使用它来避免错误而不是防止威胁。

final keyword is not used for this kind of security. It is not a substitute for what would normally require a cryptographic solution.

What is usually meant by "security" in these kinds of discussions is the concept of a secure object model - that is to say an object model that cannot be manipulated by consumers for purposes unintended by the original author of the class.

It's Sort of, a well-constructed class will encapsulate its state and a class that only has final methods will not allow consumers to override the behavior of the class and change how the state is encapsulated. A class could expose its state (through public fields for example) and no final keyword would be able to protect the integrity of that state.

It is more about "changing" the stuff rather than "securing". The final keywords simply puts away the ability to change/modify/extend any method.

It doesn't make your code more secure, it is more for thread safety than anything else. If a variable is marked final, a value must be assigned to it when the object is created. After object creation, that variable cannot be made to refer to another value.

This behavior allows you to reason about the state of an object and make certain assumptions when multiple threads are accessing it concurrently.

I don't think that making a field final would add security against malicious attacks (more likely against mistakes and of course threading issues). The only "real form" of security is that if you have a final constant field it might get inlined at compilation so changing its value at runtime would have no impact.

I've heard of final and security more in the context of inheritance. By making a class final you can prevent someone from subclassing it and touching or overriding its protected members, but again I would use that more to avoid mistake than to prevent threats.

流殇 2024-11-30 16:06:33

假设您向公众发布了一些精美的 SWC 库。在这种情况下,您可以防止方法被覆盖。

package
{
    import flash.display.Sprite;

    public class FinalDemo extends Sprite
    {
        public function FinalDemo()
        {
            super();
            var someClientInstance:ExtendedAPIClient = new ExtendedAPIClient();
            // doSomething is overridden by ExtendedAPIClient
            someClientInstance.doSomething();
            // activate cannot be overridden
            someClientInstance.activate("mySecretAPIKey");

            var myApp:MySupaDupaApplication = new MySupaDupaApplication(someClientInstance);

        }
    }
}

/**
 * Assume this class is within a swc that you release to the public.
 * You want every developer to get some APIKey
 * */
internal class MySupaDupaApplication{
    public function MySupaDupaApplication($apiClient:APIClient):void{
        if($apiClient.activated)trace("It's a valid user, do something very cool");
    }
}

/**
 * In order to activate a Client the developer needs to pass a 
 * instance of the API Client to the Application.
 * The application checks the activated getter in order to determine
 * if the api key is valid.
 * */
internal class APIClient{

    private var __activated:Boolean = false;

    public function APIClient(){        
        trace("APIClient Constructor");
    }

    /**
     * override possible
     * */
    public function doSomething():void{
        trace("doing something");
    }

    /**
     * override not possible
     * */
    public final function activate($key:String):void{
        trace("activate "+$key);
        if($key == "mySecretAPIKey"){
            __activated = true;
        }else{
            __activated = false;
            throw new Error("Illegal Key");
        }
    }

    /**
     * override not possible
     * */
    public final function get activated():Boolean{
        return __activated;
    }   
}

/**
 * Class within some developers library using MySupaDupaApplication
 * Changes the Client behaviour
 * Exploit of activation not possible
 * */
internal class ExtendedAPIClient extends APIClient{

    public function ExtendedAPIClient(){
        trace("ExtendedAPIClient Constructor");
        super();
    }

    override public function doSomething():void{
        trace("doing something else");
    }

    /* this will throw a compiler error */
    /*
    override public function activate($key:String):void{
        // do nothing
    }

    override public function get isActivated($key:String):Boolean{
        return true;
    }   
    */  
}

Assume you release some fancy SWC Library to the public. In this case you can prevent a method from beeing overridden.

package
{
    import flash.display.Sprite;

    public class FinalDemo extends Sprite
    {
        public function FinalDemo()
        {
            super();
            var someClientInstance:ExtendedAPIClient = new ExtendedAPIClient();
            // doSomething is overridden by ExtendedAPIClient
            someClientInstance.doSomething();
            // activate cannot be overridden
            someClientInstance.activate("mySecretAPIKey");

            var myApp:MySupaDupaApplication = new MySupaDupaApplication(someClientInstance);

        }
    }
}

/**
 * Assume this class is within a swc that you release to the public.
 * You want every developer to get some APIKey
 * */
internal class MySupaDupaApplication{
    public function MySupaDupaApplication($apiClient:APIClient):void{
        if($apiClient.activated)trace("It's a valid user, do something very cool");
    }
}

/**
 * In order to activate a Client the developer needs to pass a 
 * instance of the API Client to the Application.
 * The application checks the activated getter in order to determine
 * if the api key is valid.
 * */
internal class APIClient{

    private var __activated:Boolean = false;

    public function APIClient(){        
        trace("APIClient Constructor");
    }

    /**
     * override possible
     * */
    public function doSomething():void{
        trace("doing something");
    }

    /**
     * override not possible
     * */
    public final function activate($key:String):void{
        trace("activate "+$key);
        if($key == "mySecretAPIKey"){
            __activated = true;
        }else{
            __activated = false;
            throw new Error("Illegal Key");
        }
    }

    /**
     * override not possible
     * */
    public final function get activated():Boolean{
        return __activated;
    }   
}

/**
 * Class within some developers library using MySupaDupaApplication
 * Changes the Client behaviour
 * Exploit of activation not possible
 * */
internal class ExtendedAPIClient extends APIClient{

    public function ExtendedAPIClient(){
        trace("ExtendedAPIClient Constructor");
        super();
    }

    override public function doSomething():void{
        trace("doing something else");
    }

    /* this will throw a compiler error */
    /*
    override public function activate($key:String):void{
        // do nothing
    }

    override public function get isActivated($key:String):Boolean{
        return true;
    }   
    */  
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文