URL 路径元素中的标识符是否有任何安全隐患?
Are there any security implications of identifiers in URL path elements?
我正在使用 Devise 实现一个 Rails 应用程序来完成大部分用户身份验证工作。我注意到的一件事是,在为安全敏感任务传递标识符时,它们总是使用查询字符串参数来完成。
例如,发送给用户的密码重置电子邮件中包含的 URL 可能如下所示:
http://example.com/users/password/edit?reset_password_token=_aPKoNpLHm7HYs_o4Qex
Devise 根据 reset_password_token
查找用户并在用户重置表单时更改密码。
我刚刚实现了 Devise 未处理的类似功能。在每封电子邮件中,我都包含一个退订 link。控制器根据唯一令牌查找用户并将其取消订阅标志设置为 true,即使用户未登录也是如此。
然而,我生成的 URL 看起来像这样:
http://example.com/subscription/3e7eb22a268b62d5/edit
基本上,这与 Devise 正在做的事情是一样的。区别在于我在 URL 路径本身而不是查询字符串中包含了令牌。
在我看来,这更像是 RESTful,因为它指向用户随后更新的特定资源(有问题的订阅)(通过将表单发布到 PUT http://example.com/subscription/3e7eb22a268b62d5
)。除了这个好处,我看不出这两种方法有什么区别。
有什么原因让我无法在 RESTful URL 上使用查询字符串参数吗?
在 URL 中传递令牌在 RESTful 服务中并不是很好。更好的方法是在请求内容中发送它。也就是说,这个令牌是一次性的,与身份验证并没有真正相关,所以它可能不那么烦人......而且我想这个功能需要从 link (在电子邮件中)不是来自表单提交,这就是为什么使用这样的 URL 参数。
否则,在资源路径 (http://example.com/subscription/3e7eb22a268b62d5/edit
) 中诚实地使用操作(元素 edit
)名称并不是真正的 RESTful ;-) 事实上,操作是由使用的方法本身。在方法 POST
的情况下,如果您想支持多个操作,我们最终还可以使用额外的提示。
关于方法 PUT
的使用,当您想要更新资源的完整表示时应该使用它。在您的情况下,我认为您更像是方法 POST
的情况,因为您想使用重置密码令牌对订阅执行操作(重置订阅的密码)。这是我在您的案例中看到的请求:
POST http://example.com/subscription/3e7eb22a268b62d5
{
"reset_password_token": "_aPKoNpLHm7HYs_o4Qex"
}
我为您提供两个 link 可以帮助您设计您的请求:
- https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/。有点离题但在相同的上下文中(身份验证令牌、刷新令牌...)
根据 Craig Walker 的评论进行编辑。
希望对你有帮助,
蒂埃里
Is there something reason I'm missing to use a query string parameter
over a RESTful URL?
不是真的。 user a query parameter 和 not 之间唯一真正的区别是一些干预系统可能不会缓存带有查询参数的 URI,因此在这种情况下,在基本 URI 中嵌入标识符是一种解决方法。
也就是说,该论点与您的用例几乎无关。
在高层次上,REST 根本不关心,因为它将 URI 视为一个整体(并且查询参数是 URI 的一部分)。因此,它对此事没有任何建议。两个 URI 都是唯一的 "name the resource",因此 REST 很高兴。
习惯上,在 BASE URI 中嵌入 id 非常流行,它可能与边缘情况缓存场景相关,因此,这是唯一真正支持该形式而不是查询参数的人。
在外观上,许多人更喜欢嵌入式样式。
我会让你权衡这些因素。
我正在使用 Devise 实现一个 Rails 应用程序来完成大部分用户身份验证工作。我注意到的一件事是,在为安全敏感任务传递标识符时,它们总是使用查询字符串参数来完成。
例如,发送给用户的密码重置电子邮件中包含的 URL 可能如下所示:
http://example.com/users/password/edit?reset_password_token=_aPKoNpLHm7HYs_o4Qex
Devise 根据 reset_password_token
查找用户并在用户重置表单时更改密码。
我刚刚实现了 Devise 未处理的类似功能。在每封电子邮件中,我都包含一个退订 link。控制器根据唯一令牌查找用户并将其取消订阅标志设置为 true,即使用户未登录也是如此。
然而,我生成的 URL 看起来像这样:
http://example.com/subscription/3e7eb22a268b62d5/edit
基本上,这与 Devise 正在做的事情是一样的。区别在于我在 URL 路径本身而不是查询字符串中包含了令牌。
在我看来,这更像是 RESTful,因为它指向用户随后更新的特定资源(有问题的订阅)(通过将表单发布到 PUT http://example.com/subscription/3e7eb22a268b62d5
)。除了这个好处,我看不出这两种方法有什么区别。
有什么原因让我无法在 RESTful URL 上使用查询字符串参数吗?
在 URL 中传递令牌在 RESTful 服务中并不是很好。更好的方法是在请求内容中发送它。也就是说,这个令牌是一次性的,与身份验证并没有真正相关,所以它可能不那么烦人......而且我想这个功能需要从 link (在电子邮件中)不是来自表单提交,这就是为什么使用这样的 URL 参数。
否则,在资源路径 (http://example.com/subscription/3e7eb22a268b62d5/edit
) 中诚实地使用操作(元素 edit
)名称并不是真正的 RESTful ;-) 事实上,操作是由使用的方法本身。在方法 POST
的情况下,如果您想支持多个操作,我们最终还可以使用额外的提示。
关于方法 PUT
的使用,当您想要更新资源的完整表示时应该使用它。在您的情况下,我认为您更像是方法 POST
的情况,因为您想使用重置密码令牌对订阅执行操作(重置订阅的密码)。这是我在您的案例中看到的请求:
POST http://example.com/subscription/3e7eb22a268b62d5
{
"reset_password_token": "_aPKoNpLHm7HYs_o4Qex"
}
我为您提供两个 link 可以帮助您设计您的请求:
- https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/。有点离题但在相同的上下文中(身份验证令牌、刷新令牌...)
根据 Craig Walker 的评论进行编辑。
希望对你有帮助, 蒂埃里
Is there something reason I'm missing to use a query string parameter over a RESTful URL?
不是真的。 user a query parameter 和 not 之间唯一真正的区别是一些干预系统可能不会缓存带有查询参数的 URI,因此在这种情况下,在基本 URI 中嵌入标识符是一种解决方法。
也就是说,该论点与您的用例几乎无关。
在高层次上,REST 根本不关心,因为它将 URI 视为一个整体(并且查询参数是 URI 的一部分)。因此,它对此事没有任何建议。两个 URI 都是唯一的 "name the resource",因此 REST 很高兴。
习惯上,在 BASE URI 中嵌入 id 非常流行,它可能与边缘情况缓存场景相关,因此,这是唯一真正支持该形式而不是查询参数的人。
在外观上,许多人更喜欢嵌入式样式。
我会让你权衡这些因素。