Может ли секрет быть скрыт в «безопасном» Java-классе, предоставляющем учетные данные для доступа? - PullRequest
8 голосов
/ 23 апреля 2011

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

Вот что я имею в виду:

public final class Safe {

    private String secret;
    private HashMap<String, Credentials> validCertificates
            = new HashMap<String, Credentials>();

    public Safe(String aSecret) {
        this.secret = aSecret;
    }

    public final class Credentials {
        private String user;
        private Credentials(String user) {
            this.user = user;
        }
    }

    public final Credentials getCredential(String user) {
        // Following test is just for illustrating the intention...
        if ( "accepted".equals(user) ) {
            return new Credentials(user);
        } else {
            return null;
        }
    }

    public String gimmeTheSecret(Credentials cred) {
        if ( this.validCertificates.get(cred.user) == cred ) {
            return secret;
        } else {
            return null;
        }
    }

    private void writeObject(ObjectOutputStream stream) throws IOException {
        throw new RuntimeException("No no no no no no no!!!");
    }

}

Можно ли это улучшить?Должно ли это быть улучшено?Возможно ли реализовать идею блокировки секрета в безопасном классе?

РЕДАКТИРОВАТЬ

Актуальность:

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

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

Уточнение:

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

Факты:

  • Чтобы реализовать защиту в приложении Java, необходимо установить экземпляр SecurityManager, где проверка методы переопределяются по мере необходимости
  • Это приложение может загружать недоверенный код с безопаснымзагрузчики классов и назначьте домен защиты для классов, которые он загружает.Этот домен не должен включать в себя RuntimePermission ("setSecurityManager").
  • Ненадежный код может пытаться изменить SecurityManager, но поскольку загрузчик защищенных классов не предоставилВ разрешении setSecurityManager будет выдано исключение SecurityException.

Решенные проблемы:

Что касается среды выполнения, нам нужно выделить два случая:

  • Контролируемая среда: Мы запускаем приложение, которое будет использовать ненадежный код, пытаясь взломать наш «сейф».

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

  • Неконтролируемая среда: Хакер может запустить приложение, которое использует ненадежный код, пытаясь взломать наш «сейф».

Хакер может создать свое собственное приложение со своим собственным менеджером безопасности и загрузчиком Secure Class.Он может загрузить наш код из пути к классам и выполнить его, как если бы это было наше собственное приложение.В этом случае он может взломать сейф.

Ответы [ 12 ]

12 голосов
/ 23 апреля 2011

Эта «охрана» смехотворна.

Где она работает?На моем рабочем столе?Я подключаюсь к JVM с помощью отладчика и просматриваю все секреты открытым текстом.

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

Или я внедряю свой собственный кодмодификация через BCEL и модификатор конструктора Safe для выгрузки «секретного» значения в файл.

Или я просто заменяю весь пакет на мой с тем же именем, помещая его в загрузчик классов начальной загрузки.

Или я могу даже изменить и скомпилировать исходные коды Java для получения модифицированной JVM.

Или ... мой, можно перечислить десятки способов извлечения значения из экземпляра среды выполнения!

Настоящий вопрос в любой системе безопасности: кто злоумышленник ?Какова модель угрозы?Без ответа эта тема бессмысленна.

12 голосов
/ 23 апреля 2011

Нет, это не безопасно от другого кода Java. Ваш секрет может быть получен из экземпляра Safe, например:

Field field = safe.getClass().getDeclaredField("secret");
field.setAccessible(true);
String secret = (String) field.get(safe);

Обновление: Если вы контролируете загрузку другого Java-кода, от которого хотите скрыть секрет, вы, вероятно, можете использовать пользовательский SecurityManager или ClassLoader для предотвращения доступа к нему. Вы должны контролировать среду, в которой это работает, хотя, например, сервер, к которому вы ограничиваете доступ.

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

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

4 голосов
/ 23 апреля 2011

Вы можете сделать секрет «трудным» для доступа, но вы не можете сделать его невозможным.Есть поговорка (Брюс Шнайер, я верю): против обычного пользователя все работает.Против решительного взломщика ничего не работает.

1 голос
/ 01 мая 2011

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

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

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

Окончательное решение - разместить недоверенный код в своей собственной фиктивной локальной сети. (Что-то, что они сделали для анализа червя stuxnet.;)

1 голос
/ 30 апреля 2011

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

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

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

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

Третий момент, когда у вас есть физический доступ к компьютеру, вы можете делать все, что угодноВ частности, это включает в себя шпионаж во всем, что делает программа.И все содержимое компьютера.Да, контент может быть зашифрован, но при использовании он больше не шифруется.Это серьезная проблема системы открытых / закрытых ключей: закрытый ключ где-то хранится, поэтому вы должны быть уверены, что это место безопасно.

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

Банковские компьютеры являются доверенными, и предоставляемый доступ к внешнему слову действительно ограничен и контролируется.Они «безопасны».

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

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

Безопасность на стороне клиента основана на доверии, которое вы можете иметь на клиенте.Если вы можете доверять ему, это прекрасно, это работает.Если вы не можете, то он сломан.

1 голос
/ 27 апреля 2011

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

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

1 голос
/ 23 апреля 2011

http://code.google.com/p/joe-e/ - это подмножество объектных возможностей java, которое предназначено для обеспечения разложимой безопасности - способность одной части программы сохранять свои свойства безопасности, даже когда другие части программы находятся под контролем, скомпрометированы или манипулирует злоумышленником.

Тем не менее, действительным JVM разрешено расширять семантику языка с помощью дополнительных языковых средств, таких как возможность подключать отладчик во время выполнения. Код, который может использовать Runtime для вызова доступа к оболочке, может подключить отладчик ко многим стандартным JVM и обойти ограничения доступа private, даже если JVM настроена так, что нормальное отражение учитывает поле private ness.

Joe-E запрещает множество злоупотреблений сокрытием информации, которые могут усложнить это, и, конечно, запрещает нефильтрованный доступ к Runtime.

0 голосов
/ 09 октября 2013

Добавление комментария для всех, кто натыкается на эту старую ветку ....

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

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

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

0 голосов
/ 30 апреля 2011

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

Java предоставляет 3 объекта разрешений, связанных с реализацией безопасности:

PrivateCredentialPermission SecurityPermission AuthPermission

Они могут помочь улучшить и контролировать доступ к функциональным возможностям при реализации криптографической системы.Их обязательно достаточно для обеспечения безопасности системы.

0 голосов
/ 28 апреля 2011

Предполагая, что информация, передаваемая в вызовы методов, является безопасной, ключ является хорошим решением.Ключ не должен храниться где-либо в приложении, и из-за этого доступ к информации невозможен только через Java.Будет интересно, если вы захотите поделиться секретом с другими, не передавая им свой ключ, для чего ниже приведен метод shareSecret.Тем не менее, становится сложно управлять этим.Один процесс может быть:

1) Секретный искатель запрашивает доступ, вводя временный ключ, который хранится

2) Секретный хранитель предоставляет доступ со своим ключом, временный ключ удаляется, иСоздается временный безопасный объект, который работает с временным ключом.

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

Опять же, предполагая, что параметры, передаваемые в вызовы методов, безопасны, основная проблема с вышеописанной процедурой заключается в том, что кто-то мог взломать временный ключ от 1 до 2 и использовать его для просмотра временного секрета между шагами 2 и 3Однако взломать его будет сложнее, чем хранить его в виде простой текстовой строки.

public final class Safe {
    private String secret;

    public Safe(String secret, String key){
        this.secret = encode(secret, key}

    public String getSecret(String key){
        return decode(this.secret, credentials);
    }

    public Safe shareSecret(String fromKey, String toKey){
        return new Safe(decode(this.secret, fromKey), toKey); 
    }

    private String encode(String secret, String key){
       //Code to encode the secret based on key here...
    }

    private String decode(String secret, String key){
       //Code to decode the secret based on key here...
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...