414 URI слишком длинный. Но не всегда

У меня есть следующий URL-адрес для сброса пароля:

http://example.com/resetPassword/LtoyURJd5AYuP3KEGg4gx8fvUprT37LBQDlvhg22qjg=.eyJ0b2tlbiI6IiQyeSQxMCRMTlgzU29HdEdOaExsay5yQ1puQ2ZlZ1wvbVNcL09BMDV2SjhcL1wvcHNRNjZaQmRpbWpOdnhGQlciLCJ0aW1lIjoiMjAxNS0xMi0xMVQwOTozOToyOSswMTAwIiwiZW1haWwiOiJsb3JlbS51dC5hbGlxdWFtQGZldWdpYXRwbGFjZXJhdHZlbGl0Lm9yZyJ9

На локальной машине разработки все работает без проблем. Но на общедоступном сервере (размещенном на amazon ec2) я получаю 414 Uri слишком длинным. Я пытался исправить это, но я не могу решить проблему. PS: я заменил URL на example.com

Я попытался добавить следующую строку в /etc/apache2/apache2.conf, файл vhosts conf. Как одновременно, так и по отдельности. И да. Я также каждый раз перезапускал службу apache.

LimitRequestLine 8190

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

http://example.com/robotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsr/robotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsroborobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobots.txtrobots.txtrobots.txtrobots.txtrobots.txtrobots.txtrobots.php?test=ok
http://example.com/robotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsr/robotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsroborobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobotsrobots.txtrobots.txtrobots.txtrobots.txtrobots.txtrobots.txtrobots.php
http://example.com/robots.txt?klsadjflkasdjflkdsajflkdsja=sdakjflksadjfoaiwsefnalkfjsdakjflksadjfoaiwsefnalkfjsdakjflksadjfoaiwsefnalkfjsdakjflksadjfoaiwsefnalkfjsdakjflksadjfoaiwsefnalkfjsdakjflksadjfoaiwsefnalkfjsdakjflksadjfoaiwsefnalkfj

Я также переместил robots.txt в другое место и сделал для него правило перезаписи. Даже тогда, кажется, работает правильно. Так что mod_rewrite не может быть проблемой.

Проблема возникает, когда URL-адрес становится длиннее +/- 275 символов. Он работал со ссылкой сброса 273, а более длинная была 324 символа. Я думаю, что длинный URL-адрес робота составлял около 400 символов.

У меня также, похоже, проблема (с которой я не уверен, связана она или нет), что мои виртуальные хосты загружаются неправильно. Сервер всегда перенаправляет на путь, определенный по умолчанию. Не vhosts. Вывод apache2ctl -s дает следующее:

ubuntu@ip-172-31-28-19:~$ apache2ctl -S                                                                                                                                                                                                                                                               
VirtualHost configuration:
<ip>:80        example.com (/etc/apache2/apache2.conf:228)
ServerRoot: "/etc/apache2"
Main DocumentRoot: "/var/www/public"
Main ErrorLog: "/var/log/apache2/error.log"
Mutex proxy: using_defaults
Mutex default: dir="/var/lock/apache2" mechanism=fcntl 
Mutex mpm-accept: using_defaults
Mutex watchdog-callback: using_defaults
Mutex rewrite-map: using_defaults
PidFile: "/var/run/apache2/apache2.pid"
Define: DUMP_VHOSTS
Define: DUMP_RUN_CFG
User: name="www-data" id=33 not_used
Group: name="www-data" id=33 not_used

Обновление 2015-12-18 В ходе обсуждения с другими разработчиками в моей команде мы выберем другой базовый образ для этого сервера на Amazon. Казалось, что проблем больше, чем это. Так что этот вопрос устарел.


person Niek de Gooijer    schedule 14.12.2015    source источник
comment
Просто мысль, выполняет ли контроллер resetPassword (или что-то еще) перенаправление и является ли целевая страница перенаправления причиной 414?   -  person DjB    schedule 14.12.2015
comment
Нет, это просто get, который проверяет ключ и дает соответствующий ответ. Либо форма для сброса, либо сообщение о том, что пошло не так.   -  person Niek de Gooijer    schedule 14.12.2015
comment
Вы пытались изменить LimitRequestFieldSize?   -  person Robert    schedule 17.12.2015
comment
Необходимо учитывать длину специальных символов, измененную на %xx (x3).   -  person Breaking not so bad    schedule 17.12.2015
comment
Можете ли вы использовать POST вместо GET?   -  person Gary    schedule 17.12.2015
comment
Вы уверены, что 414 генерируется Apache? Вы записали дословный HTTP-ответ? Возможно, есть какие-то посредники.   -  person covener    schedule 17.12.2015
comment
Кроме того, это действительно похоже на правило перенаправления или перезаписи, которое генерирует повторяющийся шаблон. Посмотрите в свой журнал Apache и посмотрите, что запрашивается.   -  person Gary    schedule 17.12.2015
comment
Есть ли причина для такого длинного ключа проверки? Я имею в виду, что ключа длиной 20 символов было бы достаточно.   -  person Charlotte Dunois    schedule 18.12.2015
comment
@Роберт. Да, я пробовал это.   -  person Niek de Gooijer    schedule 18.12.2015
comment
@ Гэри, это ссылка из почты. так что никаких бланков. И какой повторяющийся узор?   -  person Niek de Gooijer    schedule 18.12.2015
comment
@Ковенер. нет, я не уверен. я посмотрю на это. Но nginx не установлен.   -  person Niek de Gooijer    schedule 18.12.2015
comment
@Карлотта Дюнуа. Что ж. ключ действительно мог быть короче. Первая часть — это ключ, сгенерированный из последней части. последняя часть представляет собой массив json в кодировке base64. Это гарантирует отсутствие закалки третьими лицами.   -  person Niek de Gooijer    schedule 18.12.2015
comment
Я заметил, что в вашем образце URL-адреса символ 46 закодированной части представляет собой точку (.). Возможно ли, что сервер интерпретирует другие сотни символов как абсурдно слишком длинное расширение файла? Вы пробовали кодировать URL-адрес этой точки в %2E   -  person tbernard    schedule 23.12.2015
comment
Как говорится в обновлении вопроса. Мы настроили совершенно чистый новый сервер. и на новом сервере работает вроде без проблем. Но спасибо за участие :)   -  person Niek de Gooijer    schedule 23.12.2015


Ответы (4)


Вместо того, чтобы base64_encode() вводить информацию, необходимую для сброса пароля, со всей информацией, доступной всем для base64_decode() ее, см. это:

// this is from your example
$encoded = 'eyJ0b2tlbiI6IiQyeSQxMCRMTlgzU29HdEdOaExsay5yQ1puQ2ZlZ1wvbVNcL09BMDV2SjhcL1wvcHNRNjZaQmRpbWpOdnhGQlciLCJ0aW1lIjoiMjAxNS0xMi0xMVQwOTozOToyOSswMTAwIiwiZW1haWwiOiJsb3JlbS51dC5hbGlxdWFtQGZldWdpYXRwbGFjZXJhdHZlbGl0Lm9yZyJ9';

$data = json_decode(
    base64_decode($encoded), 
    true
);

// array (
//     'token' => '$2y$10$LNX3SoGtGNhLlk.rCZnCfeg/mS/OA05vJ8//psQ66ZBdimjNvxFBW',
//     'time' => '2015-12-11T09:39:29+0100',
//     'email' => '[email protected]',
// )

Сохранять данные в таблице

Как насчет того, чтобы вместо этого сохранить эти данные — либо в базе данных, либо в другом месте с ограниченным сроком действия — и затем либо использовать UUID, либо хэш, созданный с этими данными выше, в качестве идентификатора для сброса пароля?

CREATE TABLE `password_reset` (
  `id` char(40) NOT NULL DEFAULT '',
  `token` char(60) NOT NULL DEFAULT '',
  `time` datetime NOT NULL,
  `email` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Идентификатор из SHA-1

Затем сгенерируйте свой идентификатор:

$id = sha1(serialize([
    'token' => '$2y$10$LNX3SoGtGNhLlk.rCZnCfeg/mS/OA05vJ8//psQ66ZBdimjNvxFBW',
    'time' => '2015-12-11T09:39:29+0100',
    'email' => '[email protected]',
    'foo' => microtime(), // for some variation
]);

Сохраните данные в своей таблице, и там у вас будет идентификатор фиксированной длины, а URL-адрес сброса пароля станет

http://example.com/resetPassword/0f4d2541c25ba8edbb3cd6df362d7dbf6317d7a5

Идентификатор как UUID

Вместо того, чтобы использовать sha1() для создания хэша из каких-то входных данных, вероятно, было бы лучше использовать, например, ramsey/uuid для создания основанного на времени UUID (фиксированная длина, 36 символов):

use Ramsey\Uuid\Uuid;

$id = Uuid::uuid1()->toString()

Хотя это не решает вашу проблему разрешения очень длинных URI, но решает проблему лучше и безопаснее.

Бонус

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

person localheinz    schedule 23.12.2015
comment
Я сохранил токен, который находится внутри строки base64, в базе данных. Но я использую электронную почту, чтобы убедиться, что токены принадлежат этому запросу. Я согласен с тем, что люди могут читать данные. И никто не может изменить эти данные без моего ведома. Но спасибо за очень хороший ответ и предложения! - person Niek de Gooijer; 23.12.2015

Используйте метод POST вместо get, и это решит вашу проблему.

Но если вы по-прежнему хотите использовать метод «GET» вместо метода «POST», то в Apache значение LimitRequestLine можно изменить на что-то большее, чем значение по умолчанию 8190, если вы хотите поддерживать более длинный URI запроса.

Если вы не можете найти LimitRequestLine в конфигурационном файле apache, просто добавьте строку самостоятельно в любом месте. например: LimitRequestLine 100000

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

person Alpesh Panchal    schedule 23.12.2015
comment
Вопрос касается ссылки для сброса пароля, которая, как вы, вероятно, знаете, отправляется на электронную почту пользователя, чтобы щелкнуть ее, что делает использование POST невозможным вариантом. - person Achraf Almouloudi; 24.12.2015

Есть как минимум 2 переменные конфигурации, которые могут вызвать ошибку 414.

Директива LimitRequestLine позволяет администратору сервера установить предел допустимого размера строки HTTP-запроса клиента. По умолчанию это 4094.

Директива LimitRequestFieldSize позволяет администратору сервера установить предел допустимого размера поля заголовка HTTP-запроса. По умолчанию это 4094 байта.

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

Полезные ссылки:

person Robert    schedule 17.12.2015
comment
Я уже добавил в конфигурацию параметры LimitRequestFieldSize и LimitRequestLine. Так что ничего не делает. Я также понятия не имею, как я могу увидеть, насколько велик запрос. - person Niek de Gooijer; 17.12.2015
comment
захватите его через браузер или перейдите в свой собственный файл журнала или файл /var/log/apache2 и проверьте запрос - person Robert; 17.12.2015

Вы не должны использовать этот шаблон, даже если он работает после изменения образа EC2.

В вашем примере схема + хост, то есть http://example.com, имеет длину 18 байт. Если ваш фактический хост имеет аналогичную длину, ограничение в 275 символов может означать, что к пути применяется ограничение в 255 символов.

Какой бы ни была причина, RFC 2068 не рекомендует использовать более длинные URI (хотя спецификация требует, чтобы серверы могли для обработки любой длины URI):

Серверы должны быть осторожны в зависимости от длины URI выше 255 байт, потому что некоторые старые реализации клиента или прокси-сервера могут не поддерживать эту длину должным образом.

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

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

person avnr    schedule 23.12.2015