Как нельзя использовать «финал» как проблему безопасности? - PullRequest
9 голосов
/ 13 июля 2011

Со страницы 113 O'Reilly's Essential ActionScript 3.0 (2007):

Методы, которые являются окончательными, помогают скрыть внутренние детали класса.Создание класса или метода final не позволяет другим программистам расширять класс или переопределять метод с целью изучения внутренней структуры класса.Такое предотвращение считается одним из способов защиты приложения от злонамеренной эксплуатации .

Относится ли это к пользователям API скомпилированного пакета с закрытым исходным кодом и"злонамеренно эксплуатируется", чтобы узнать вещи о дизайне класса?Это действительно проблема?

Для большего контекста, это вторая из двух причин использования final.В выпуске 2007 года он находится на странице 113 в главе Наследование под подзаголовком Предотвращение расширения классов и переопределение методов .

Последний атрибутиспользуется в ActionScript по двум причинам:

  • В некоторых ситуациях финальные методы выполняются быстрее, чем не финальные.Если вы хотите улучшить производительность вашего приложения всеми возможными способами, попробуйте сделать его методы окончательными.Однако обратите внимание, что в будущих версиях Flash Adobe ожидает, что не финальные методы будут выполняться так же быстро, как и финальные методы.

  • Методы, которые являются окончательными, помогают скрыть внутренние детали класса.Создание класса или метода final не позволяет другим программистам расширять класс или переопределять метод с целью изучения внутренней структуры класса.Такое предотвращение считается одним из способов защиты приложения от злонамеренной эксплуатации.

Ответы [ 3 ]

8 голосов
/ 13 июля 2011

Во многих языках переопределение методов является обязательным для базового класса. Зачастую это ключевое слово virtual, которое позволяет авторам базового класса включить возможность переопределения.

В AS3, однако, возможность переопределения методов отключена. Вот что делает ключевое слово final. Это позволяет автору базового класса сказать «этот метод не может быть переопределен».

Есть некоторые идеи старой школы об инкапсуляции, которые позволяют предположить, что для AS3 проблема безопасности заключается в том, чтобы сделать это таким образом. Но это в основном в случае общедоступных API, в которых вы хотите скрыть свой контент, но раскрыть функциональность.

Но в более современные времена мы узнали, что дизассемблирование и рефлексия позволят злонамеренному разработчику в любом случае делать все, что он / она хочет, поэтому сегодня это не проблема. Полагаю, что final для обеспечения безопасности является опорой, на мой взгляд, и любые предложения по этому поводу следует отклонить. О безопасности нужно думать более тщательно, чем это. API-интерфейсы должны быть спроектированы таким образом, чтобы реализация позволяла разработчикам делать то, что им тогда нужно, но информация, критичная для безопасности, не должна включаться в общедоступные API-интерфейсы.

Это не значит, что final бесполезен. final сообщает разработчикам, унаследованным от вашего класса, что вы никогда не предназначали им переопределить функцию Он позволяет вам сказать «пожалуйста, просто вызовите эту функцию. Не переопределяйте». Это скорее интерфейс или коммуникационный механизм, чем все остальное, ИМО.

1 голос
/ 13 июля 2011

конечное ключевое слово не используется для такого рода безопасности. Это не замена того, что обычно требует криптографического решения.

В таких обсуждениях обычно подразумевается понятие «безопасность» - концепция защищенной объектной модели, то есть объектной модели, которой потребители не могут манипулировать в целях, не предусмотренных первоначальным автором класса.

Это своего рода, хорошо сконструированный класс будет инкапсулировать свое состояние, а класс, имеющий только конечные методы, не позволит потребителям переопределить поведение класса и изменить способ инкапсуляции состояния. Класс может раскрыть свое состояние (например, через открытые поля), и никакое ключевое слово не сможет защитить целостность этого состояния.

Это больше о "изменении" материала, чем о "защите". Последние ключевые слова просто убирают возможность изменять / модифицировать / расширять любой метод.

Это не делает ваш код более безопасным, это больше для безопасности потоков, чем что-либо еще. Если переменная помечена как финальная, ей необходимо присвоить значение при создании объекта. После создания объекта эта переменная не может быть привязана к другому значению.

Это поведение позволяет вам рассуждать о состоянии объекта и делать определенные предположения, когда несколько потоков обращаются к нему одновременно.

Я не думаю, что выход в финал игры повысит безопасность от злонамеренных атак (более вероятно, от ошибок и, конечно, от проблем с многопоточностью). Единственная «реальная форма» безопасности состоит в том, что если у вас есть последнее поле констант, оно может быть встроено во время компиляции, поэтому изменение его значения во время выполнения не окажет влияния.

Я слышал о финале и безопасности больше в контексте наследования. Сделав финал класса, вы можете помешать кому-либо разделить его на подклассы и коснуться или переопределить его защищенные члены, но я бы опять использовал это больше, чтобы избежать ошибки, чем для предотвращения угроз.

0 голосов
/ 13 июля 2011

Предположим, что вы выпустили какую-то необычную библиотеку 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;
    }   
    */  
}
...