【问题标题】:How could not using "final" be a security issue?不使用“final”怎么可能是一个安全问题?
【发布时间】:2011-07-13 07:59:31
【问题描述】:

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

final 方法有助于隐藏类的内部细节。制作一个类或一个 方法 final 防止其他程序员扩展类或覆盖 用于检查类的内部结构的方法。这种预防 被认为是保护应用程序不被 被恶意利用

这是否是指使用已编译的封闭源代码包的 API 并“被恶意利用”来学习有关类设计的东西的用户?这真的是个问题吗?

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

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

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

  • final 方法有助于隐藏类的内部细节。制作一个类或一个 方法 final 防止其他程序员扩展类或覆盖 用于检查类的内部结构的方法。这种预防 被认为是保护应用程序不被 被恶意利用。

【问题讨论】:

    标签: actionscript-3 oop final


    【解决方案1】:

    在许多语言中,覆盖方法是从基类中选择加入的。通常,virtual 关键字允许基类作者选择是否可以覆盖。

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

    有一些关于封装的老派想法表明,AS3 以这种方式进行封装是一个安全问题。但这主要是在您希望隐藏内容但公开功能的公共 API 的情况下。

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

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

    【讨论】:

      【解决方案2】:

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

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

      有点像,一个结构良好的类会封装它的状态,而一个只有 final 方法的类将不允许消费者重写类的行为并改变封装状态的方式。一个类可以公开其状态(例如通过公共字段),并且没有 final 关键字能够保护该状态的完整性。

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

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

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

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

      我听说过更多关于继承的 final 和 security。通过将类设为 final,您可以防止某人对其子类化并触及或覆盖其受保护的成员,但我再次使用它来避免错误而不是防止威胁。

      【讨论】:

      • final 确实有助于减少错误。引起我注意的是“恶意利用”。你是说final不影响恶意攻击?
      • 这不是“抵御攻击”意义上的“安全”。这更像是“更难搞错”。我更喜欢“安全”这个词;我觉得这更像是预防事故,而不是恶意。
      • 我同意; final 提供了这种安全性/安全性。这本书声称这可以防止恶意攻击,这与无意的错误不同。
      【解决方案3】:

      假设您向公众发布了一些精美的 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;
          }   
          */  
      }
      

      【讨论】:

      • 我想你可以称它为安全性:) 通过反编译字节码来解决似乎微不足道。
      • 据我了解,这是提到的安全问题。但是你是对的,反编译是一个严重的安全问题,即使你使用了一些代码加扰器。因此,所有关键流程都应在网络服务器上实施。 :-)
      猜你喜欢
      • 1970-01-01
      • 2014-01-27
      • 1970-01-01
      • 1970-01-01
      • 2014-01-27
      • 2023-03-13
      • 2011-04-08
      • 2010-10-02
      • 2011-11-24
      相关资源
      最近更新 更多