Безопасность во Flex - можно ли манипулировать загруженным кодом и запускать веб-сервис - PullRequest
1 голос
/ 24 февраля 2009

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

Хитрость заключается в том, что не все наши веб-сервисы являются грубозернистыми. Чтобы привести пример, у нас может быть два метода веб-сервиса: EnoughFounds и Transfer. Таким образом, только после того, как метод EnoughFounds ответит «true», я выполню Transfer. Эта логика программируется внутри кода приложения Flex.

Сценарий, который мне представлен, следующий: что если кто-то загрузит приложение и декомпилирует его. Затем он изменяет код, поэтому шаг EnougFunds не выполняется. Или, может быть, пишет совершенно новый клиент, может быть, даже в другой технологии, которая будет выполнять Transfer без прохождения шага EnoughFunds. При выполнении Transfer пользователь будет авторизован и аутентифицирован на сервере; но поскольку он использует свои настоящие учетные данные, он сможет выполнить перевод. Пропущенная им проверка относится к бизнес-логике, а не к области безопасности. Мне нужно как-то убедиться, что код, выполняющий приложение, является неизмененным кодом Flex, который я написал и скачал пользователем. Как я могу это сделать? Я знаю, что могу переписать службы так, чтобы последовательность выполнялась на сервере, но это требует значительных усилий, и я ищу какое-то другое решение.

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

Обратите внимание, что я не ищу советов по передовым методам. Мое требование - ничего не менять на стороне сервера. Как я могу защитить последовательность на уровне протокола, не меняя услуги?

Ответы [ 6 ]

17 голосов
/ 24 февраля 2009

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

В частности, имеет смысл использовать операцию EnoughFunds, потому что если EnoughFunds возвращает false, вы можете сказать пользователю, что у него недостаточно средств. Однако операция Transfer должна проверить, достаточно ли средств, и не зависеть от клиента для такой важной проверки.

9 голосов
/ 24 февраля 2009

Позвольте мне добавить этот бит - у меня есть дети, декомпилирующие мои игры и изменяющие / редактирующие сообщения, отправляемые туда-сюда с помощью инструментов, которые управляют передачей http - и это только для игр, у которых нет снаружи значение. Мои пользователи фактически загружают инструменты заголовков fiddler и firefox, чтобы манипулировать сервисными вызовами, просто чтобы получить высокий балл на игровой доске, которая сбрасывается каждый день.

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

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

6 голосов
/ 05 марта 2009

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

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

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

Это означает, что даже если вы добавите в протокол логику безопасной последовательности, которая гарантирует, что EnoughFunds был вызван перед «Transfer» и вызван только один раз, и не так давно, и с правильными параметрами, это все еще клиент говорит банку "все нормально, у меня достаточно средств". Который просто не собирается сокращать это, когда-либо.

Самое близкое, что вы могли бы получить - это эквивалент банковского клиента, наклонившегося над прилавком, указывающего на экран сотрудника и говорящего: «Посмотрите, в вашей системе , он говорит, что транзакция может быть выполнена» потому что средств достаточно ", т.е. е. клиент может достоверно воспроизводить время, ввод и вывод вызова EnoughFunds, который сервер только что сделал , что нормально, но совершенно бессмысленно.

Итак, решение состоит в том, чтобы перевести EnoughFunds на внутренний счет, период . Если клиенту необходимо знать, вы можете вернуть описательное исключение / ошибку, если средств недостаточно.

It's like this.
(источник: userfriendly.org )

5 голосов
/ 06 марта 2009

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

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

Ваш «домен доверия» распространяется только на веб-сервис API и не далее. Если ваш сервис не может проверить целостность своих операций, то это плохо спроектированный сервис.

1 голос
/ 03 марта 2009

Я думаю, вы должны рассмотреть несколько вещей:

0 голосов
/ 01 марта 2009

Во-первых, я согласен с другими ответами - клиент абсолютно ваш враг, и ему никогда не следует доверять. Чтобы также расширить некоторые комментарии, которые вы разместили - даже если «EnoughFunds» возвращает какой-то зашифрованный токен, это означает, что он еще не был вызван хакером с суммой 10, а последующая передача была активирована с суммой 10000000.

Подход должен состоять в том, чтобы объединить атомарную бизнес-логику, такую ​​как «EnoughFunds and Transfer».

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

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

Это можно сочетать с запутыванием вашего API. Если вы называете веб-сервисы по их названию (например, сервис EnoughFunds будет называться именно так), то реэкспроектировать становится намного проще. Вместо этого сделайте что-нибудь простое, например, перечислите сервисы, и пройдите через центральный контроллер - activTask = 12? Param1 = 200. Это все еще довольно легко перепроектировать, хотя ... Так что лучше, если вы сможете инвестировать в шифрование каждого запроса в целом, чтобы он выглядел так: SFASDFsdq1231sd4DFGTRsdf2rDF

И, конечно, любое такое хорошее шифрование запроса должно быть частично основано на идентификаторе сеанса (обычно это токен аутентификации при входе)

...