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

У меня есть следующий url для reset моего пароля:

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

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

Я попытался добавить следующую строку в /etc/apache 2/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 символов. Он работал с ссылкой reset 273, и дольше было 324 символа. Я думаю, что длинный URL-адрес роботов составлял 400 символов.

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

[email protected]:~$ 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 При обсуждении с другими разработчиками в моей команде мы будем выбирать другое базовое изображение для этого сервера на амазонке. Казалось, было больше проблем, чем это. Поэтому этот вопрос устарел.

Ответы

Ответ 1

Вместо base64_encode() введите информацию, необходимую для reset пароля, со всей информацией, которую есть для всех, чтобы 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 или хеша, созданного с этими данными выше, как идентификатор пароля reset?

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
]);

Храните данные в своей таблице, и там у вас есть идентификатор фиксированной длины, а ваш пароль reset URL становится

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

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

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

use Ramsey\Uuid\Uuid;

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

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

Bonus

Посмотрите на OWASP Забыли пароль Cheatsheet и связанный, возможно, это поможет сделать ваше приложение более безопасным!

Ответ 2

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

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

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

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

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

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

Таким образом, единственным решением является сохранение информации reset на стороне сервера и указание URI на нее с более коротким токеном.