Кодировать/обфускировать параметры HTTP

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

Например, URL выглядит как /webapp?user=Oscar&count=3

Мы хотели бы иметь что-то вроде: /webapp?data=EDZhjgzzkjhGZKJHGZIUYZT и декодировать это значение на сервере с реальной информацией о запросе.

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

У нас есть Java на сервере и JavaScript на клиенте.


person OscarRyz    schedule 25.10.2010    source источник
comment
Если вы публикуете из формы, параметры не будут частью URL   -  person DwB    schedule 25.10.2010
comment
Как я понимаю, обфускация — это когда данные скрыты из-за сложности (например, операции ROT13 или XOR), шифрование — это когда вы должны знать секрет для доступа к данным.   -  person Gary Rowe    schedule 26.10.2010
comment
Для потомков; Я не помню этот проект, но я точно помню, что принятый ответ Майка Атласа - это правильный путь: работать над аутентификацией/авторизацией в приложении.   -  person OscarRyz    schedule 27.02.2020


Ответы (6)


Нет, не делай этого. Если вы можете создать что-то в своем клиентском коде, чтобы запутать данные, передаваемые обратно на сервер, то и преднамеренный хакер сможет это сделать. Вы просто не можете доверять данным, отправляемым на ваш сервер, независимо от того, что делает ваш официальный клиент. Придерживайтесь экранирования данных клиента и проверки их по белому списку на стороне сервера. Используйте SSL и, если можете, поместите параметры запроса в POST вместо GET.

Редактировать расширение

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

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

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

Итак, чтобы подвести итог:

  1. Безопасность путем обфускации вовсе не является безопасностью.
  2. Вы не можете доверять данным пользователя, даже если они скрыты. Проверьте свои данные.
  3. Использование безопасных каналов связи (SSL) помогает блокировать другие связанные угрозы.
  4. Вам следует отказаться от своего подхода и поступить правильно. Правильным в вашем случае, вероятно, является добавление механизма аутентификации с системой привилегий, чтобы пользователи не могли получить доступ к вещам, для просмотра которых у них недостаточно привилегий, включая то, к чему они могут попытаться получить доступ, подделав параметры GET. ответ Гэри Р., а также комментарий Дэйва и Уилла попали в этот глава.
person Mike Atlas    schedule 25.10.2010
comment
Итак, ваша рекомендация: Не делать этого, потому что это не идеально? Я действительно не понимаю, как я могу проверить данные клиента. Например, если URL-адрес /getinfo?user=oscar, как я могу проверить по белому списку значение: Оскар. Разве использование SSL + POST не будет таким же простым, как и их отсутствие? - person OscarRyz; 25.10.2010
comment
@OcarRyz, для вашего примера здесь вы можете захотеть зарегистрировать пользователя в своем приложении и использовать идентификатор сеанса, хранящийся в файле cookie, для проверки его личности для будущих запросов. Затем, когда они попытаются просмотреть информацию об Оскаре, вы можете подтвердить, что Оскар существует, и что пользователь либо сам Оскар, либо кто-то, у кого есть разрешение на просмотр информации об Оскаре. - person Dave Aaron Smith; 26.10.2010
comment
Мне нравится этот ответ. Да, U всегда должен проверять правильность ввода на стороне сервера, несмотря ни на что! Кроме того, если вы сохраните немного осмысленной строки запроса, это даст разработчикам мэшапов доступ к некоторым интересным вещам на вашем веб-сайте, если он захочет! - person Markandey Singh; 26.10.2010
comment
@Оскар - на первый взгляд, проблема, с которой вы здесь имеете дело, - это не проблема подделки данных, а проблема авторизации. Кого волнует, если кто-то попросит информацию об Оскаре, если они не уполномочены видеть Оскара, то они ничего не получат. Если это так, и вас это беспокоит, необходимо реализовать полную схему авторизации ролей и привилегий лодки, а не пытаться не допустить, чтобы пользователи задавали плохие вопросы через запросы на взлом. - person Will Hartung; 26.10.2010
comment
Я получаю больше от комментариев Дейва и Уилла, чем от ответа Майка. Я действительно не знаю, подразумевает ли ответ Майка эти два комментария, и в этом случае я бы отметил его как принятый. По крайней мере, Уилл может отредактировать ответ Майка, чтобы добавить комментарий. - person OscarRyz; 26.10.2010
comment
ооо, наверное это только я, но я не понял. Какой тогда ответ? Использовать SSL и POST? что мне не хватает? - person OscarRyz; 26.10.2010
comment
Я отредактировал свой ответ, чтобы попытаться разрешить вашу путаницу, но я подозреваю, что вам действительно следует добавить систему аутентификации / привилегий, а не систему запутывания URL-адресов. Последнее подходит для хорошей публикации thedailywtf.com. Ответ Гэри Р., вероятно, правильный. - person Mike Atlas; 26.10.2010
comment
@Mike Спасибо за рекомендацию @Oscar Вы можете проверить эту ссылку static .springsource.org/spring-security/site/faq/faq.html, в котором подробно описан подход Spring Security к этой проблеме. - person Gary Rowe; 26.10.2010
comment
Ответ заключается в том, чтобы выполнить проверку на сервере. Например, если пользователь пытается получить доступ к данным Оскара, выполните проверку на сервере, чтобы убедиться, что они должны видеть данные Оскара, прежде чем предоставлять их им. Если они пытаются выполнить действие только для администратора, не просто скрывайте кнопку для пользователей, не являющихся администраторами, но на сервере убедитесь, что они являются администраторами, прежде чем выполнять это действие. - person Yuliy; 26.10.2010

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

SALT = "so9dnfi3i21nwpsodjf";

function computeUrl(url) {
  return url + "&hash=" + md5(url + SALT );
}

function checkUrl(url) {
  hash = /&hash=(.+)/.match(url);
  oldUrl = url.strip(/&hash=.+/);
  return md5(oldUrl + SALT ) == hash;
}
person Dave Aaron Smith    schedule 25.10.2010
comment
Что вы имеете в виду, когда ваше приложение генерирует URL-адрес? Вы имеете в виду, когда клиент генерирует запрос? - person Mike Atlas; 25.10.2010
comment
@Mike, я предполагаю, что строки URL будут исходить из серверной части приложения. Например, возможно, приложение сделает что-то вроде <a href="<?PHP echo(computeUrl("/webapp?user=Oscar&count=3"))?>">Get 3 of these.</a> - person Dave Aaron Smith; 25.10.2010
comment
Это ломается довольно быстро, если какой-либо из параметров находится в элементах управления вводом формы. - person Mike Atlas; 25.10.2010
comment
@Майк, очень хороший момент. Я считаю, что все, кроме самых простых форм, нарушит любой подход, кроме более тонкой проверки на стороне сервера, которую вы обсуждаете в своем ответе. Подход на стороне клиента можно было бы взломать с помощью firebug, а подход на стороне сервера, отличный от того, что вы описываете, был бы бесполезен. - person Dave Aaron Smith; 25.10.2010
comment
@jbinto, я не совсем понимаю. Здесь ничего не расшифровывается. Я генерирую и сравниваю хэши, чтобы обеспечить целостность данных. Возможно, часть путаницы в том, что я неправильно назвал PRIVATE_KEY. Это действительно должно называться SALT, как в решении @Will. - person Dave Aaron Smith; 26.10.2010

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

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

Здесь есть золотое правило: запрещать все, кроме того, что, как вы знаете, безопасно.

person Gary Rowe    schedule 25.10.2010

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

Тогда вы можете просто:

http://example.com/service?x=123&y=Bob&sig=ABCD1324

Этот метод раскрывает данные (т. е. они могут «видеть», что xyz=123), но не могут изменить данные.

Есть преимущество «шифрования» (и я использую этот термин вольно). Здесь вы шифруете весь раздел параметров URL-адреса.

Здесь вы можете сделать что-то вроде:

http://example.com/service?data=ABC1235ABC

Хорошая вещь в использовании шифрования двояка.

Во-первых, он защищает данные (например, пользователь никогда не увидит, что xyz=123).

Другая особенность заключается в том, что он расширяемый:

http://example.com/service?data=ABC1235ABC&newparm=123&otherparm=abc

Здесь вы можете декодировать исходную полезную нагрузку и выполнить (безопасное) слияние с новыми данными.

Таким образом, запросы могут ДОБАВЛЯТЬ данные к запросу, но не изменять СУЩЕСТВУЮЩИЕ данные.

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

Очевидно, вы не хотите делать НИЧЕГО из этого на клиенте. Нет никакого смысла. Если вы можете это сделать, «они» могут это сделать, и вы не заметите разницы, поэтому вы можете вообще не делать этого — если только вы не хотите «шифровать» данные через обычный HTTP-порт (в отличие от TLS, но тогда люди будут мудро задаваться вопросом «зачем беспокоиться»).

Для Java вся эта работа выполняется в фильтре, как я это сделал. Задний конец изолирован от этого.

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

Это также то, что я сделал.

Недостатком является то, что это очень сложно сделать правильно и эффективно. Вам нужен легкий синтаксический анализатор HTML для извлечения URL-адресов (я написал потоковый синтаксический анализатор, чтобы делать это на лету, чтобы он не копировал всю страницу в ОЗУ).

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

Также существует некоторая особая обработка при работе с Javascript (поскольку ваш фильтр не будет легко «знать», где находится URL-адрес для шифрования). Я решил эту проблему, потребовав, чтобы URL-адреса были подписаны так, чтобы они были конкретными «var signedURL='....'», поэтому я могу легко найти их в выводе. Не такое уж бремя для дизайнеров, как вы могли бы подумать.

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

Больно делать, но в целом приятно.

person Will Hartung    schedule 25.10.2010
comment
Разве большинство людей не сделали бы это, сохранив данные в сеансе на стороне сервера? Мне кажется, что это подход MS ViewState. - person UpTheCreek; 27.04.2013

Что-то вроде jCryption?

http://www.jcryption.org/examples/

person oimoim    schedule 25.10.2010
comment
Нужен ли мне интерпретатор javascript на стороне сервера? - person OscarRyz; 25.10.2010
comment
Нет, просто взгляните на включенный php-файл (encrypt.php) и перепишите его на java :) - person oimoim; 26.10.2010

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

person Florian    schedule 25.10.2010