Вопрос

У меня возникли проблемы с пониманием того, почему так важно безопасное кодирование Java.Например, почему так важно объявлять переменные закрытыми?Я имею в виду, я понимаю, что это сделает невозможным доступ к этим переменным извне класса, но я мог бы просто декомпилировать класс, чтобы получить значение.Аналогично, определение класса как final сделает невозможным создание подкласса этого класса.Когда выделение подкласса в класс может быть опасным для безопасности?Опять же, при необходимости я мог бы декомпилировать исходный класс и переопределить его любым вредоносным кодом, который мне только захочется.Возникает ли проблема, когда пользователь "доверяет" приложениям?И люди могли бы тогда каким-то образом злоупотребить этим доверием?По сути, то, что я ищу, - это хороший пример того, почему следует следовать рекомендациям по безопасному кодированию.

Это было полезно?

Решение

Программирование - это сложно.

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

Причины кроются в первую очередь не в "безопасности", как при сохранении секретности, а в ясности, простоте и понятности.

В качестве бонуса, гораздо проще заставить вещи работать правильно, если вы можете знать, что пользователь API, конечно, не меняет "ваши" переменные за вашей спиной.

Другие советы

Это "безопасно" означает, что внутренняя работа класса скрыта от того, кто его использует.

Термин безопасный не используется, поскольку в разделе "защита сервера" используется для обозначения того факта, что пользователю одного класса не нужно беспокоиться о том, как класс выполнит задачу, которую он хочет от него выполнить.

Беру с тебя пример:

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

Java - это объектно-ориентированное программирование langauge, и одним из ключевых понятий в объектно-ориентированном программировании является инкапсуляция.

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

Используя эту концепцию, хотелось бы скрыть внутренние состояния с помощью private переменные, предотвращающие непосредственное влияние других объектов на внутренние состояния.В Java обычно можно увидеть геттеры и сеттеры (например getColor и setColor) для того, чтобы работать с объектами.

Кроме того, инкапсуляция также может повысить надежность кода.

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

В качестве убедительного примера, скажем, что был Score объект, который должен был иметь percent значение между 0 и 100.Предоставляя setPercent(int) метод, который проверяет, что указанное значение находится в пределах допустимого диапазона, предотвратил бы Score объект от перевода в неприемлемое состояние.

Итак, пытаясь напрямую манипулировать внутренним состоянием, написав оператор типа score.percent = 150 можно было бы предотвратить, если бы setPercent метод вызывает ошибку или выдает Exception если указанное значение неприемлемо.

Здесь есть две проблемы.

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

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

Например, если у вас есть класс square с защищенной функцией getArea(), вы ожидаете вернуть площадь квадрата.Однако можно создать новый класс, который расширяет квадрат, скажем, класс rectangle расширяет квадрат.Теперь rectange может переопределить getArea(), но он по-прежнему имеет тип square, что может нарушить что-то, что зависит от этой функциональности square.Делая свой класс окончательным, вы утверждаете, что этого никогда не может произойти в вашей системе.

Этот тип "безопасного кодирования" не помешает кому-либо увидеть ваш исходный код, но он помогает сделать ваш код более надежным и пригодным для использования в будущем.

Просто чтобы добавить к тому, что уже сказали другие:Некоторые из этих функций также можно просто рассматривать как способ заявить о намерении.Если я стану участником private Я делаю "невозможным" доступ к нему для других (это возможно, но здесь это не имеет значения), но что более важно, я говорю пользователям, что это деталь реализации, на которую они не должны полагаться.

просто представьте, что у вашего объекта есть внутреннее свойство, которое не является закрытым (hidden), и ваш код, обращающийся к этому свойству, случайно выполняется в многопоточной среде, поэтому N потоков начнут обращаться к нему одновременно, 5 потоков хотели бы изменить это свойство, 4 - прочитать.Вы никак не можете убедиться, что все будет работать аккуратно, ни один поток не будет знать, какие данные он хранит в данный момент, и успешно ли он изменил свойство этого объекта.

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

Короче говоря, у вас огромная проблема, и отладка - это кошмар, поскольку вы не знаете, когда данные были заблокированы, какой поток это сделал, откуда это произошло и т.д.

Только один сценарий того, что произойдет, если вы не инкапсулируете...

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

Термин "безопасное кодирование" относится к созданию программного обеспечения, которое явно пытается избежать уязвимостей в системе безопасности, будь то на C, Java, Ruby, языке ассемблера или чем-либо еще.Возможно, самой важной частью этого, после выбора безопасной языковой системы, является соблюдение передовых методов программирования.Если программа неясна, то у вас мало шансов на то, что она заслуживает какого-либо доверия.

Для Java есть два примечательных руководства:

В Java существует два различных режима безопасного кодирования.

В одном случае вы имеете дело с кодом, который, возможно, не обладает всеми привилегиями, присущими вашему коду.Например, если вы пишете библиотеку или подписываете код, вам необходимо это делать.Вредоносный код не должен использовать ваши разрешения непреднамеренным образом.Это очень сложно!

Чаще всего вы имеете дело с программами, которые имеют дело только с ненадежными данными.Например, веб-серверы (например, XSS и SQL-инъекции) и настольные прикладные программы, работающие с ненадежными файлами (обычно проблема заключается в коде на C, имеющем переполнение буфера - подлинный C ++ лучше).В некоторых ситуациях отказ в обслуживании (DoS) может быть серьезной проблемой.

Здесь есть некоторое совпадение.Например, интерпретаторы запускаются с разрешениями кода интерпретатора и могут быть довольно "мощными".

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top