【问题标题】:414 URI too long. But not always414 URI 太长。但不总是
【发布时间】:2016-03-19 23:55:13
【问题描述】:

我有以下网址可以重置我的密码:

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

在本地开发机器上它可以正常工作。但是在公共服务器(托管在亚马逊 ec2 上)上,我得到了一个 414 Uri。我试图修复它,但我似乎无法解决问题。 ps:我已将 url 替换为 example.com

我尝试将以下行添加到 /etc/apache2/apache2.conf,即 vhosts conf。既是同时又是分开的。是的。我也每次都重启了apache服务。

LimitRequestLine 8190

另外,当我请求其他长网址时,也没有问题。例如。我重命名了 robots.txt,所以我可以请求以下网址:

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 个字符。我认为机器人的长网址大约有 400 个字符。

我似乎也有我的虚拟主机没有正确加载的问题(我不知道这是否相关)。服务器总是重定向到默认定义的路径。不是虚拟主机。 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 日更新 在与我团队中的其他开发人员讨论时,我们将为亚马逊上的该服务器选择不同的基础映像。似乎还有比这更多的问题。所以这个问题已经过时了。

【问题讨论】:

  • 只是想一想,resetPassword 控制器(或其他)是否进行了重定向,重定向着陆页是否会导致 414?
  • 不,它只是一个验证密钥并给出适当响应的获取。重置表单或发送错误消息。
  • 您尝试过更改 LimitRequestFieldSize 吗?
  • 特殊字符长度改为%xx (x3) 必须考虑..
  • 你确定 414 是 Apache 生成的吗?您是否捕获了逐字 HTTP 响应?也许有一些中介。

标签: php apache amazon-ec2 virtualhost apache2.4


【解决方案1】:

而不是base64_encode()ing 你需要重置密码的信息,所有的信息都在那里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' => 'lorem.ut.aliquam@feugiatplaceratvelit.org',
// )

将数据保存在表中

不如将这些数据持久化——无论是在数据库中还是在其他生命周期有限的地方——然后使用 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' => 'lorem.ut.aliquam@feugiatplaceratvelit.org',
    '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 的 Forgot Password Cheatsheet 和相关的,也许它有助于使您的应用程序更安全!

【讨论】:

  • 我已经持久化了数据库中持久化的 base64 字符串中的令牌。但我使用电子邮件来验证令牌是否属于此请求。我对人们能够读取数据感到满意。在我不知情的情况下,不可能有人更改这些数据。但是感谢您提供非常好的答案和建议!
【解决方案2】:

使用 POST 方法代替 get,它会解决您的问题。

但是如果您仍然想使用“GET”方法而不是“POST”方法,那么在 Apache 下,如果您想支持更长的请求,可以将 LimitRequestLine 的值更改为大于默认值 8190 的值URI。

如果您在 apache 配置文件中找不到 LimitRequestLine,只需在您喜欢的任何位置添加该行即可。例如:LimitRequestLine 100000

但是,请注意,如果您确实遇到了这个限制,那么您可能一开始就滥用了 GET。您应该使用 POST 来传输此类数据——尤其是因为您甚至承认您正在使用它来更新值

【讨论】:

  • 问题是关于密码重置链接,您可能知道,该链接会发送到用户的电子邮件以单击它,这使得使用 POST 成为不可能的选项。
【解决方案3】:

至少有 2 个配置变量会导致 414 错误。

LimitRequestLine 指令允许服务器管理员设置客户端 HTTP 请求行的允许大小限制。默认为 4094。

LimitRequestFieldSize 指令允许服务器管理员设置 HTTP 请求标头字段的允许大小限制。默认为 4094 字节

尝试同时增加它们或尝试查看到达服务器的请求有多大。如果您将发送到服务器的请求放在这里可能会很有用。

有用的链接:

【讨论】:

  • 我已经在配置中添加了 LimitRequestFieldSize 和 LimitRequestLine。所以这没有任何作用。我也不知道如何才能看到请求有多大。
  • 通过浏览器捕获它或转到您的自定义日志文件或 /var/log/apache2 文件并检查请求
【解决方案4】:

您不应该使用这种模式,即使它在更改 EC2 映像后仍然有效。

在您的示例中,架构 + 主机,即http://example.com,长度为 18 个字节。如果您的实际主机具有相似的长度,则 275 字符限制可能表示路径上应用了 255 个字符的限制。

无论出于何种原因,RFC 2068 建议不要使用更长的 URI(尽管规范要求服务器能够处理任何 URI 长度):

服务器应谨慎使用超过 255 字节的 URI 长度,因为一些较旧的客户端或代理实现可能无法正确支持这些长度。

因此,您点击的电子邮件客户端很可能会通过一些发出 414 代码的内部代理(例如反网络钓鱼)重定向点击。这就是 Zimbra 的工作方式。这是电子邮件客户端的常见做法,以减少来自恶意链接的威胁。在这种情况下,POST 对您没有帮助,因为您无法从电子邮件客户端进行 POST。

所以唯一的解决方案是在服务器端持久化重置信息,并让 URI 用更短的令牌指向它。

【讨论】:

    猜你喜欢
    • 2019-06-02
    • 1970-01-01
    • 2022-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-31
    相关资源
    最近更新 更多