414 URI too long. But not always
Asked Answered
E

4

14

I have the following url to reset my password:

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

On the local development machine it works without any problems. But on the public server (hosted on amazon ec2) i get a 414 Uri to long. I have tried to fix it but i can't seem to solve the issue. ps: i have replaced the url to example.com

I have tried adding the following line to /etc/apache2/apache2.conf, the vhosts conf. Both at the same time and seperate. And yes. I also restarted apache service every time.

LimitRequestLine 8190

Also when i request other long url's there is no problem. For example. i renamed robots.txt so i could request the following urls:

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

I also moved robots.txt to a other location and made a rewrite rule for it. Even then it seems to work correct. So mod_rewrite does not seme to be the problem.

The problem occurs when the url becomes longer as +/- 275 chars. It worked with a reset link of 273 and the longer was 324 chars. The robots long url was arround 400 chars i think.

I also seem to have the problem (which i am not shure is related or not) that my vhosts is not loaded correctly. The server always redirects to the path defined in the default. Not of the vhosts. apache2ctl -s output gives the following:

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

Update 2015-12-18 In discussion with the other developers in my team we will be choosing a different base image for this server on amazon. There seemed to be more problems than this. So this question has become obsolete.

Elamitic answered 14/12, 2015 at 13:19 Comment(14)
Just a thought, does the resetPassword controller (or whatever) do a redirect and is the redirect landing page causing the 414?Interpolate
No it is just a get that validates the key and gives the appropriate response. Either form for reset or message what went wrong.Elamitic
have you tried changing LimitRequestFieldSize?Ekaterinburg
The length of special characters changed to %xx (x3) has to be taken into account..Kannry
Can you use a POST instead of GET?Chrysotile
Are you sure the 414 is generated by Apache? Did you capture the verbatin HTTP response? Maybe some intermediary is in place.Ranit
In addition, this really sounds like a redirect or rewrite rule that is generating a repeating pattern. Look in your Apache log and see what is being requested.Chrysotile
Is there any reason for such a long validation key? I mean, a 20 characters long key would be sufficient.Homovec
@Robert. Yes i tried that.Elamitic
@Chrysotile it is a link from a mail. so no forms. And what repeating pattern?Elamitic
@Covener. no i am not shure. il look into that. But no nginx installed.Elamitic
@Cahrlotte Dunois. Well. the key could be shorter indeed. The first part is a key generated from the last part. the last part is a base64 encoded json array. This ensures no tempering by third parties.Elamitic
I noticed in your sample URL character 46 of encoded part is a dot (.). Is it possible the server is interpreting the other however many hundred characters as an absurdly too long file extension?? Have you tried URL encoding that dot to %2ECelestinacelestine
Like states in the question update. We have configured a entirely clean new server. and it works like without problems on the new server. But thanks for the input :)Elamitic
D
4

Instead of base64_encode()ing the information you need to reset a password, with all the information there for everyone to base64_decode() it, see this:

// 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]',
// )

Persist data in a table

How about instead persisting that data - either in a database or elsewhere with limited lifetime - and then either using a UUID or a hash created with that data above as an identifier for the password 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;

Identifier from SHA-1

Then generate your identifier:

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

Store the data in your table, and there your have your fixed length identifier, and your password reset URL becomes

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

Identifier as UUID

Instead of using sha1() to create a hash from some input, it would probably be better to use, for example, ramsey/uuid to generate a time-based UUID (fixed length, 36 characters):

use Ramsey\Uuid\Uuid;

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

While this doesn't solve your problem of allowing really long URIs, it solves the problem in a better, much safer way.

Bonus

Have a look at OWASP's Forgot Password Cheatsheet and related, maybe it helps in making your application more secure!

Doloresdolorimetry answered 23/12, 2015 at 12:37 Comment(1)
I have persisted the token that is inside the base64 string persisted in the database. But i use the email to verify that the tokens belongs to this request. I am ok with people being able to read the data. And it is not possible for someone to change this data without me knowing. But thanks for the very nice answer and suggestions!Elamitic
C
1

Use POST method instead of get and it will resolve your problem.

But if you still would like to use "GET" method instead of "POST" method, then under Apache, value of LimitRequestLine can be changed to something larger than its default of 8190 if you want to support a longer request URI.

If you can't find LimitRequestLine into apache config file, just add the line yourself anywhere you like. e.g: LimitRequestLine 100000

However, note that if you're actually running into this limit, you are probably abusing GET to begin with. You should use POST to transmit this sort of data -- especially since you even concede that you're using it to update values

Clute answered 23/12, 2015 at 11:21 Comment(1)
The question is about a password reset link, which as you probably know, gets sent to the user's email to click it, which makes using POST an impossible option.Harday
E
0

There are at least 2 config variables that can cause 414 error.

LimitRequestLine directive allows the server administrator to set the limit on the allowed size of a client's HTTP request-line. By default it is 4094.

LimitRequestFieldSize directive allows the server administrator to set the limit on the allowed size of an HTTP request header field. By default it is 4094 bytes

Try increase both of them or try to see how big is request that comes to server. It could be useful if you put here the request that you send to server.

Useful links:

Ekaterinburg answered 17/12, 2015 at 8:16 Comment(2)
I have already added both the LimitRequestFieldSize and LimitRequestLine in the configuration. So that does nothing. I also have no idea how i can see how big the request is.Elamitic
capture it via browser or go to your custom log file or /var/log/apache2 file and check requestEkaterinburg
G
0

You shouldn't use this pattern even if it works after changing the EC2 image.

In your example the schema + host, i.e. http://example.com, is 18 bytes long. If your actual host has a similar length then the 275 char limitation might indicate that a limit of 255 characters is applied on the path.

Whatever the reason, RFC 2068 advises against longer URIs (although the spec requires servers to be able to handle any URI length):

Servers should be cautious about depending on URI lengths above 255 bytes, because some older client or proxy implementations may not properly support these lengths.

So it is very possible that the email client from which you click is redirecting the click via some internal proxy (such as anti-phishing) that issues the 414 code. This is for example how Zimbra works. It is common practice in email clients in order to reduce threats from malicious links. In that case a POST won't help you because you cannot POST from an email client.

So the only solution is to persist the reset information on the server side, and have the URI point to it with a shorter token.

Gastritis answered 23/12, 2015 at 20:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.