Насколько легко взломать JavaScript (в браузере)?

37

Мой вопрос касается безопасности JavaScript.

Представьте себе систему аутентификации, в которой вы используете среду JavaScript, такую ​​как Backbone или AngularJS , и вам нужны защищенные конечные точки. Это не проблема, поскольку сервер всегда имеет последнее слово и проверит, авторизованы ли вы делать то, что вы хотите.

Но что, если вам нужно немного безопасности без участия сервера? Это возможно?

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

Насколько легко пользователю изменить эту переменную и получить доступ?

Мои знания по безопасности (и JavaScript) не велики. Но если переменная не находится в глобальной области видимости и находится в закрытой части шаблона модуля, который имеет только геттеры, но не сеттеры, даже в этом случае, вы можете разобраться с этим?

Хесус Родригес
источник
29
Все эти длинные ответы. Короче говоря, чтобы ответить вам заголовок, "очень взломать". Чтобы ответить на ваши первые 2 вопроса, встроенные друг в друга, «без сервера вы потеряли безопасность» && «Нет». На 3-й ответ «Очень легко» и, наконец, «Да, с легкостью». Вот и ты. На все вопросы ответил. : P
SpYk3HH
Яркий пример, см. Мой пост в блоге о добавлении jQuery на любую веб-страницу. spyk3lc.blogspot.com/2013/05/… Теперь, молодой падаван, иди и попробуй. Посмотрите, насколько просто добавить jQuery на любой сайт, у которого его еще нет, а затем используйте jquery, чтобы очень легко манипулировать любой частью поля зрения без длинных строк javascript. Boom!
SpYk3HH
7
Когда-то, при регистрации доменного имени, номер телефона был обязательным полем, но это только в javascript, а не на стороне сервера. Итак, я отключил его, переопределив функцию (используя Firebug), и вуаля! У них нет моего номера телефона.
Изката
8
manipulate any part of the sight without long lines сайт против зрения
mplungjan
8
Профессиональные веб-программисты должны понять это правильно. Пожалуйста. Это смущение больше, чем нацистская грамматика :) plus.google.com/u/0/+MonaNomura/posts/h9ywDhfEYxT
mplungjan

Ответы:

26

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

Безопасная схема для связи клиент-сервер без необходимости аутентификации на сервере вручную при каждом запросе:

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

Предположим, что протокол HTTPS предотвращает атаки «человек посередине» (MITMA).

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

  • Клиент сейчас не в сети. Клиент хочет выполнить доверенные действия. Клиент вводит свой пароль и получает открытый ключ сервера.

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

  • Когда клиент находится в сети, клиент отправляет свой идентификатор клиента, и все действия, которые выполнял клиент, отправляются на сервер в зашифрованном виде с открытым ключом сервера.

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

Заметка:

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

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

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

  • Это соответствует вашему требованию о том, что «ping to the server» не выполняется. Злоумышленник не может просто имитировать HTTP-запрос с поддельными данными, если он не знает ключ.

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

  • Это довольно распространенная схема для одностраничных приложений (например, с AngularJS).

  • Я называю открытый ключ сервера «открытым» из-за того, что это означает в схемах, подобных RSA , но на самом деле это конфиденциальная информация в схеме, и ее следует защищать.

  • Я бы нигде не хранил пароль в памяти. Я бы заставлял пользователя отправлять свой «автономный» пароль каждый раз, когда он / она запускает автономный код.

  • Не катите свою собственную криптографию - используйте для аутентификации известную библиотеку, такую ​​как Stanford.

  • Прими этот совет как есть . Перед тем, как приступить к такой аутентификации в реальном критически важном приложении, проконсультируйтесь с экспертом по безопасности . Это серьезная проблема, которая и болезненная, и легко ошибиться.

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

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

Я хотел бы еще раз добавить, что мы все еще не доверяем клиенту . Вы не можете доверять клиенту в одиночку, и я думаю, что ответ Иоахима прибивает его. Мы получили только удобство: не нужно пинговать сервер перед началом работы.

Материалы по теме:

Бенджамин Грюнбаум
источник
3
«Не катите свою собственную криптографию» применяется в той же степени к протоколам, что и к примитивам, если не больше, потому что, хотя люди обычно не настолько глупы, чтобы создавать свои собственные примитивы, они думают, что могут создать протокол, который подходит , Я также не понимаю, зачем нужен RSA. Поскольку вы используете HTTPS, почему бы просто не сгенерировать 16-32-байтовый общий секрет и не требовать его отправки с будущими запросами? Конечно, если вы сделаете это, убедитесь, что вы используете постоянную проверку равенства на строку ...
Рейд
2
+1 @Reid Да, я недавно обсуждал это с экспертом по этому поводу. Я примерно основал здесь примитивную схему на протоколе, о котором я узнал (от Рабина IIRC), но, по крайней мере, до тех пор, пока не смогу найти специфику (и обосновать, например, почему в этом случае требуется асимметричное шифрование). Не используйте схему, предложенную в этом ответе, без предварительной консультации с экспертом по безопасности . Я видел, как этот подход использовался в нескольких местах, но на практике это очень мало значит, во всяком случае. Я также отредактировал ответ, чтобы улучшить это.
Бенджамин Грюнбаум
Использование подсказки добавляет мало безопасности. Злоумышленник может переопределить window.promptметод, чтобы перехватить фразу-пароль, или запустить собственное приглашение (возможно, в пределах iframe!). Поле пароля имеет одно дополнительное преимущество: символы не отображаются.
Роб W
@RobW Конечно, вся эта схема бесполезна, если страница была взломана. Если у злоумышленника есть доступ для запуска JavaScript на странице, которую мы испортили. Идея, лежащая в основе приглашения, заключалась в том, что он блокирует, но вы правы, любая выгода для безопасности, которую он обеспечивает, сомнительна. Смотрите последнюю ссылку в списке.
Бенджамин Грюнбаум
1
Прежде всего. Удивительный ответ, я думаю, что я не могу просить больше ничего. С другой стороны, я хотел сделать любимые проекты для меня (и, конечно, для тех, кто хочет его использовать), и, возможно, это излишне (или, возможно, нет). Я имею в виду, я не хочу делать ничего серьезного, и я боюсь, что я не смогу прокрутить тот вид аутентификации, который ты объяснил, недостаток знаний. Я думаю, что бросил бы простую проверку 401 или, если у меня нет никакого запроса, я просто пингую сервер каждый раз, когда я получаю доступ к таким маршрутам. Ток авторизации также является опцией (и, возможно, самая близкая вещь связана с тем, что вы объяснили здесь AFAIK). Спасибо вам :)
Иисус Родригес
89

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

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

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

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

Как только ваши данные покидают сервер, вы должны предположить, что злоумышленник имеет к ним полный доступ.

Йоахим Зауэр
источник
Спасибо. Было бы замечательно, если бы вы могли объяснить это немного больше, мои знания в области безопасности не так хороши, и единственная часть, которую я понимаю, это то, что я неправ: P. Когда вы говорите о кешировании, это только кеширование, когда сервер говорит нет? Я имею в виду, если сервер сказал «да» один раз, вы не можете кешировать это, верно?
Иисус Родригес
3
Я просто хотел бы добавить , что это возможно закрывающий доступ к переменным в браузере (например , в шаблоне модуля ваших упомянутый), особенно с помощью отладчика :)
Бенджамин Gruenbaum
2
@ BenjaminGruenbaum: не стесняйтесь расширить это в ответ, который фокусируется на JS-стороне вещей. Я дал только высокоуровневый, независимый от технологий обзор. Ответ, фокусирующийся на самом JS, тоже был бы хорош!
Йоахим Зауэр
1
Короче говоря, если какая-то информация / маршрут / что-либо еще доступна в зависимости от переменной javascript, это не будет безопасным в любом случае, потому что вы можете легко изменить эту переменную, чтобы сказать, что вам нужно для доступа к этому личному материалу.
Иисус Родригес
4
@JoachimSauer Я думаю, что это упустило бы суть этого вопроса, который вы хорошо пригвоздили. Независимо от того, какие меры безопасности принимает клиент, это может поставить под угрозу коммуникацию . Вы можете создать очень надежные системы аутентификации в JavaScript, но все это ничего не стоит в ту минуту, когда вы вставляете связь с сервером, который другие клиенты тоже считают источником правды. Весь исходный код отправляется на клиентскую сторону, умный злоумышленник может просто прочитать его и имитировать HTTP-запрос к серверу. Все, что исходит от клиента, следует рассматривать как недоверенные, если они не проверены на сервере.
Бенджамин Грюнбаум
10

В игровом сообществе есть поговорка: « Клиент в руках врага". Любой код, работающий вне защищенной области, такой как сервер, уязвим. В самом простом сценарии уязвим для того, чтобы не запускаться в первую очередь. Это решение клиента фактически запустить ваш" код безопасности ", и пользователь может просто "отказаться". Хотя с нативным кодом у вас есть, по крайней мере, автоматическое запутывание в сборке и дополнительный уровень защиты, потому что злоумышленник должен быть хорошим программистом, чтобы манипулировать этим, JS, как правило, безоблачный и в виде простого текста. Все, что вам нужно для проведения атаки, - это примитивные инструменты, такие как прокси-сервер и текстовый редактор.Заключителю по-прежнему потребуется определенный уровень знаний в области программирования, но модифицировать скрипт с помощью любого текстового редактора гораздо проще, чем вводить код в исполняемый файл.

nvoigt
источник
Сборка - это не запутывание, и кто считает, что иначе никогда не играл в военную игру
miniBill
@miniBill: хотя у опытного злоумышленника не возникнет проблем с собранным кодом, он обеспечит очень простой высокочастотный фильтр. (Увы, это академично, поскольку отмена сценариев обеспечивает минимальное повышение безопасности сценария ОП)
Писквор,
1

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

Марк Э. Хаас
источник
0

Говоря конкретно об Angular:

Защита клиентской стороны маршрута просто не существует. Даже если вы «спрячете» кнопку для этого маршрута, пользователь всегда сможет набрать ее, Angular будет жаловаться, но клиент может кодировать это.

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

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

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

отметка
источник