URI, 可寻址性, 与HTTP GET和POST的使用

本文翻译自 URIs, Addressability, and the use of HTTP GET and POST

2020.08.03 现在回头再看,也许“安全”应该翻译为“免责”。当时按字面翻译了,今天想起这个问题,觉得有些不妥。


摘要

Web体系结构的一个重要原则是所有的重要资源都可以通过URI进行识别。 这篇文章讨论了资源的URI的可寻址性与HTTP GET的HTTP GET和POST方法之间的关系。 HTTP GET提升了URI的可寻址性,因此设计人员应该采用它来进行简单查询等安全操作。 POST适用于其他类型的应用程序,其中用户请求可能会更改资源(或相关资源)的状态。 这篇文章解释了如何在考虑到体系结构,安全性和实际考虑因素的情况下为应用程序选择HTTP GET和POST。

这篇文章不讨论HTTP之外的URI方案,或HTTP / 1.1之外的协议[RFC2616]。


1. 简介

在这篇文章中,我们将讨论何时适合使用HTTP GET以及何时适合使用HTTP POST,以及这两种方法分离背后的体系结构原则。

在简介中,我们提供了说明所涵盖的一些主题的场景,总结了Web体系结构的相关原则,并提供了一张用于选择GET或POST的快速核对表。 接下来,我们讨论URI可寻址性的好处,这是区分GET和POST的主要原因。 然后,我们将定义安全交互,在这时候鼓励使用GET。然而,在考虑GET或POST时,设计人员还应该留意敏感数据的注意事项,例如密码或信用卡信息,以及其他的实际考量因素

1.1 场景

场景1:Dan购买了一部新的无线电话,并且想和他的同事分享这部电话的信息。按照电话底部“CAT.NO.43-893”的指示,Dan访问了手机制造商的网站。在网站的搜索框中输入目录编号后,Dan会得到相关信息。但是,由于网站设计人员为这个只读操作创建了一个POST Web表单而不是GET Web表单,因此Dan无法将查询结果添加为书签,或者将查询作为URI发送给他的同事(也是该厂商的潜在客户),或者获得其他通过正确使用HTTP GET查询可以获得的好处。网站设计者应该提供对目录信息的GET访问权限;参见URI可寻址性的好处

场景2:我的银行允许我通过网络读取我的支票账户的当前信息。他们为此次访问提供的URI里包含我的帐号。这是我不希望出现在URI中的敏感信息,因为当我访问从银行网站到银行的广告客户网站的链接时,我的帐户信息可能会显示在广告客户的服务器日志中。我的银行应该允许我建立安全的HTTP连接,而不是将我的帐号从URI移到POST请求的body里。这样,我不仅对通过安全连接检索信息更放心,浏览器也会知道不要把敏感信息暴露给我在安全连接后访问的下一个站点。此外,我还可以为我的帐户页面添加书签,而不会泄露敏感信息。更多相关信息,参见敏感数据的注意事项

1.2 Web体系结构的相关原则
  1. 所有重要的资源都应当由URI识别。

  2. HTTP GET是安全的;即,代理(agent,主要指浏览器;当然可能还指一些web server)不会因为访问链接而承担义务。

    原文: …agents do not incur obligations by following links.

1.3 用于选择GET或POST的快速核对表(checklist)
  • 如果满足以下条件,应该使用GET:
    • 交互更像是一个问题(即,它是一种安全的操作,例如查询,读取操作或查找)。
  • 如果满足以下条件,应该使用POST:
    • 交互更像是一个订单;
    • 交互以用户能够感知的方式(例如,订阅某种服务)来改变资源的状态;
    • 用户要对交互结果负责。

但是,在最终决定使用HTTP GET或POST之前,还请考虑敏感数据的注意事项实际考量因素

2. URI可寻址性的好处

Web体系结构以统一资源标识符(URI)开头,其通用语法由[RFC2396]定义。 Web依赖全局协议来遵循URI规则,以便我们在Web上引用、访问、描述、共享。为资源提供URI可以带来很多好处,包括:

  • 链接(linking)
  • 书签(bookMarking)
  • 缓存(caching)

如[TBL50K]中所述,“所有的语言都使用URI作为标识,这使得复用拥有了更加强大的力量:这允许使用一种语言编写的东西引用另一种语言定义的东西。URI使用还允许一种语言使用多种形式的持久化数据,标识和各种形式的等价行为。“

原文如下:

Great multiplicative power of reuse derives from the fact that all languages use URIs as identifiers: This allows things written in one language to refer to things defined in another language. The use of URIs allows a language to leverage the many forms of persistence, identity, and various forms of equivalence.

在这篇文章中,术语“URI可寻址性”意味着仅用URI就可以使一个代理执行特定类型的交互。

在某些情况下,可能需要用不同的方式与URI标识的资源进行交互。例如,W3C链接检查服务说明了从方法中分离URI的用处。链接检查器的工作原理如下(忽略此讨论的递归链接检查):对于作为HTML或XHTML文档中链接的一部分的每个HTTP URI,链接检查器使用HEAD方法收集有关URI标识的资源的信息。正如HTTP / 1.1规范所述,“HEAD方法与GET相同,只是服务器不能在响应中返回消息体(即body)。”通过使用HEAD而不是GET,链接检查器不会要求比完成其工作所需的更多(bits)。

因此,Web体系结构允许URI和方法的分离。一个URI的格式(scheme)确定一组交互方法。例如,HTTP URI格式在HTTP / 1.1 [RFC2616]中定义,它允许“用于指示请求目的的一组开放式的方法和请求头(headers)。它基于统一资源标识符(URI)提供的参考规范…用于指示要应用方法的资源。“;参见[RFC2616]的1.1节。

原文如下:

HTTP allows an open-ended set of methods and headers that indicate the purpose of a request. It builds on the discipline of reference provided by the Uniform Resource Identifier (URI), as a location (URL) or name (URN), for indicating the resource to which a method is to be applied. Messages are passed in a format similar to that used by Internet mail as defined by the Multipurpose Internet Mail Extensions (MIME).

但是,分离URI和方法是有代价的。分离意味着交互所需的一些元数据可能不是URI的一部分,所以,单独的URI不再足以使代理执行交互; URI可寻址性会因此丢失。

在下一节中,我们将更详细地介绍何时应该使用HTTP GET(因为它提升了URI的可访问性)以及何时应该使用HTTP POST。

3. 安全交互

HTTP / 1.1的9.1节讨论了安全交互。安全交互是指用户不对交互结果负责的交互。安全交互很重要,因为这些是用户可以放心浏览的交互,以及软件(例如,搜索引擎和为用户预缓存数据的浏览器)可以安全地跟踪链接的交互。用户(或者代表用户的软件代理)不会因为查询资源或点击链接而承诺任何事情。例如,“点击ABC链接,代表您同意以下条款和条件”的网站不会说明任何人(特别是搜索服务)可以与ABC建立另一个链接的事实;通过其他链接到达ABC的人甚至可能都没见过这些条款和条件。

通过在协议级别区分安全与不安全(即用户应对特定交互负责的交互)的交互:

  • 当特定操作会产生后果时(例如,订阅列表,支付费用,取消合同等),客户可以通知用户。HTTP / 1.1规范在9.1.1节中声明,“实施者应该知道软件代表用户通过互联网进行交互,并应注意让用户了解,他们要做的事可能会对他们自己和其他人产生意料之外的影响。“
  • 中介(例如,缓存)可以代表用户安全地进行处理。

在HTTP / 1.1规范的同一部分中写道,惯例是GET用于安全交互,并且不应具有进行除检索之外的操作的权限(significance)。事实上,如果你使用GET进行有副作用的交互,这会让你的系统不安全。例如,防火墙外的恶意网页发布者可能会在HTML页面中放置一个URI,这样当防火墙内的某人无意中点击该链接时,防火墙内的另一个系统上的某个功能可能就会被激活。

用户应该通过其他机制承担义务,而非点击链接。根据HTTP / 1.1规范,设计人员应该使用HTTP POST进行这些交互。

HTTP GET的设计使得交互所需的所有信息都是URI的一部分,从而提升了URI的可寻址性。使用HTTP POST时,一些意在影响资源状态更改的信息可能是协议头的一部分,而不是URI中的一部分。使用这种方法,用于标识资源结果的URI可能会更短,但是会失去URI可寻址性带来的好处。

请注意,即使不在HTTP报文的body中提供数据,也可以使用POST。在这种情况下,资源是URI可寻址的,但POST方法向客户端表明此次交互不安全,或可能有副作用。

按照惯例,当使用GET方法时,标识资源所需的所有信息都在URI中编码。 HTTP / 1.1中没有关于安全交互(例如检索)的约定,其中客户端在HTTP实体的body中而不是在URI的查询部分中向服务器提供数据。这意味着对于安全操作,URI可能很长。对于安全操作的大参数的情况不是由HTTP当前的部署直接解决的。“QUERY”、“安全POST”、“GET with BODY”等方法已经讨论过了(比如在1996年12月的IETF会议上),但没有达成共识。

WebDAV [RFC2518]使用不同的HTTP方法PROPFIND(第8.1节PROPFIND)来查询资源的属性;遗憾的是,这不会为这些查询的结果提供URI。

关于识别安全交互的其他工作包括实验性的RFC“安全响应头字段”[RFC2310]。

3.1 使用GET和POST的例子

在9.5节中,HTTP / 1.1规范列出了一些因为副作用而应该使用POST的示例应用,包括注解现有资源,在公告板、新闻组、邮件列表或类似的文章组中发布消息,以及通过新增操作扩展数据库。

是否选择,以及如何在GET和POST之间选择,取决于格式规范和应用程序上下文。例如,当HTTP URI用于HTML,SMIL和SVG中的超链接时,应用程序将确定将使用哪种方法(通常为GET)。但是,对于HTML表单和XForms,作者可以在GET和POST之间进行选择。一个含义是HTML应用程序设计者应该使用表单实现“不安全”操作(或其他需要POST的操作),即使应用程序不需要用户输入。

3.1.1 邮件列表订阅

考虑以下两种邮件列表订阅确认设计。

设计1:

  1. 用户将订阅消息发送到管理邮箱(mylist-request@example.org)。
  2. 列表处理软件向用户发送电子邮件响应,请求用户确认订阅请求,并包括到确认页面的链接。
  3. 用户点击此链接到确认页面,找到一个带有“[确认]您的订阅”按钮的表单。表单使用method =“POST”提交。
  4. 用户激活[确认]表单控件。
  5. 列表处理软件确认订阅。

设计2(不正确):

  1. 与上面的1相同
  2. 与上面的2相同
  3. 用户点击确认页面的链接,并收到通知“您的订阅已确认”。

后一种设计执行不安全操作(列表订阅)以响应具有安全方法的请求(点击来自具有GET的邮件消息的链接)。如果用户的邮件代理预先获取页面以加快浏览,用户就会在不知情的情况下确认订阅;HTTP / 1.1规范清楚地说明了这种情况下是服务端的错误;用户的邮件代理可以自由地访问链接而不用承担义务。

3.1.2 建立义务的步骤

要确定保密义务(或者付款,或者许可条款,等等),设计人员应遵循以下协议:

  1. 客户端请求访问只有接受某些保密条款的人才能查看的材料。
  2. 服务端拒绝访问,并返回带有“需要授权”的通知,和指向帐户申请表的链接。
  3. 客户端访问表单的链接,申请帐户,并同意POST请求中的条款和条件(或者通过传真、邮寄方式)。
  4. 服务端提供证书作为响应。
  5. 客户端提供证书,重新请求材料。

类似地,个人可以通过与雇主或其他组织签订契约来同意条款和条件,之后他就可以通过协议条款涵盖的某些交互(例如访问链接)合法地承担义务。

3.1.3 副作用不代表不安全的交互

一些用户交互会产生副作用(即,它们会改变服务器的状态),但却是安全的交互。比如,当服务器被设置为统计并显示站点的访问者数量时,每次用户交互都会让计数器增加。但用户不会通过这种交互承诺任何事情,因此它是安全的。

4. 敏感数据的注意事项

某些Web交互涉及敏感数据,例如密码,信用卡号,社保号和银行帐号(如方案2中所示)。

为了保护GET或POST操作传输的信息,通常使用底层安全协议,例如安全套接字层[SSL3]。通过使用GET over SSL进行安全操作,设计人员保留了URI可寻址性的一些好处,即使丢失了其他好处(例如缓存)。设计人员需要考虑使用SSL的成本,比如:

  • 建立SSL连接所需的时间。
  • 服务器上需要的内存,以便为每个请求创建(加密)数据的新的副本。

在不适合使用此类安全协议的情况下,设计人员可以使用POST来携带验证其他安全操作所需的证书或其他信息。例如,设计者可能要求超出协议层的安全性进入应用层(例如,因为服务器站点内的软件或数据队列不受信任,或者因为应用程序需要在较低层不支持的证书)。

当不适合使用SSL时,仍然可以将一些敏感数据保留在URI之外。例如,设计人员可以在HTTP头(header)中而不是在URI的查询部分中传递认证信息。

至于更广泛的数据保护问题,例如防止未经授权访问个人书签(或cookie),超出了Web体系结构的范围。

5. 实际考量因素

Web应用程序设计除了应该遵循上述原则,还要受到相关限制。例如,在设计通过URI对资源进行操作的服务时,请考虑是否存在不适合此类操作的情况。

例如,W3C HTML验证服务允许两种情况(都使用HTML表单)。使用“安全”选项,验证请求通过URI完成;表单使用GET,它为结果提供书签、链接等的URI。第二个选项允许客户端上传文档以进行验证。该选项的表单使用POST,因为:

  • 要验证的文件可能是保密的;任何指向验证结果的链接(在公共的W3C网站上)都会泄露其内容。
  • 编码整个文档的URI至少会和文档一样大,并且链接到它没什么用,因为结果总是相同的。

是否将GET与HTTP一起用于初始访问,提供用于后续访问相同信息的URI(例如,使用Content-Location)是很有用的。

5.1 国际化

接受非ASCII字符的HTML表单的设计者受到一些实现的限制和规范缺陷的考验。实现的限制与长度有关。关于multipart / form-data的HTML 4.01 [HTML401]的第17.13.4节写道,“内容类型’application / x-www-form-urlencoded’对于发送大量二进制数据或包含非ASCII字符的文本效率不高“。

这种低效率是由于octet-to-%hh的转义转换,以及许多字符需要多个字节进行编码的事实。但是虽然效率有些低,但这并不是将GET用于非ASCII字符的真正障碍。

一个更严重的问题是字符和字节之间的映射没有在US-ASCII中明确规定;参见[RFC2396]第2.1节。对于填写HTML表单所产生的查询部分,默认使用表单的字符编码。 HTML 4.01中表单元素上的accept-charset属性的定义写道:“此属性的默认值是保留字符串’UNKNOWN’。用户代理可以将此值解释为用于传输包含这个FORM元素的文档的字符编码。“

解决此限制的总的方向是共同使用UTF-8来进行字符和字节之间的映射。 UTF-8的使用已经在各种规范中定义,我们希望它将在未来的规范中被采用,并在适当的时候进一步部署。例如,我们希望XForms指定在查询部分中使用的编码始终为UTF-8。

5.2 暂时的限制

虽然Web应用程序设计必须考虑到目前广泛部署的技术的局限性,但这不应当被视为体系结构中的不变量。以下是已经在很大程度上解决的限制,它们随着错误得到修复,以及可互操作规范的范围扩大,可能会逐渐消失:

URI不能超过256个字符

这是某些服务器实现中的限制。虽然服务器会继续具有这些限制以防止DoS攻击,但URI通常至少有4000个字符,并且会随着应用程序开发人员的合法使用而发展。

当用户使用后退按钮时,将重新执行GET请求

这不是设计上的问题。 [RFC2616]的第13.13节规定:“历史机制和缓存是不同的,特别是历史机制不应试图显示资源当前状态的语义透明视图。相反,历史机制旨在准确显示用户在资源被检索时看到的信息。“

如果我通过安全协议访问页面,然后访问指向另一个页面的链接,第二个站点可以访问URI中的敏感数据。

这不是设计上的问题。 [RFC2616]的第15.1.3节规定:“由于链接的来源可能是私人信息或可能泄露其他私人信息的来源,因此强烈建议用户能够选择是否发送”Referer“字段。例如,浏览器客户端可以有一个切换开关,用于公开/匿名浏览,分别启用/禁用Referer和From信息的发送。如果指向的页面是使用安全协议传输的,客户端不应在一个(非安全的)HTTP请求头中包含Referer字段。

搜索服务不会索引URI中带有“?”的内容。

这是一种避免在某些搜索服务爬虫中无限循环的启发式算法,但它不是一种体系结构约束,而且现代的搜索服务使用了更复杂的启发式来避免循环。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值