在整个互联网上,我看到以下建议:


GET永远不要更改服务器上的数据-为此使用POST请求


这个想法的基础是什么?

如果我提供了将数据插入数据库并在GET查询字符串中传递参数的php服务,那为什么会出错呢? (我正在使用准备好的语句来处理SQL注入)。 POST请求在某种程度上更安全​​吗?

还是有历史原因?如果是这样的话,今天的建议是否有效?

评论

有一个相关的DailyWTF条目。

命令/查询分离。

感谢您提出这个问题,也感谢@Oded的口头表达,我一直都需要参考,以将提出这个问题的人发送给:)

另请参阅HTTP PUT-stackoverflow.com/questions/630453/put-vs-post-in-rest(带有关于幂等的注释)

@JoachimSauer尽管GET会将它们从爬网程序中保存下来,但根本的问题是缺少身份验证。任何脚本小子也可以将其过时。

#1 楼

这不是建议。

在HTTP协议中以此方式定义了GET。它应该是幂等且安全的。

为什么-可以缓存GET并在浏览器中刷新。一遍又一遍。

这意味着如果再次创建相同的GET,则会再次插入数据库。

请考虑如果GET成为链接并且被搜索引擎抓取,可能意味着什么。您的数据库中将充满重复的数据。

我还建议您阅读URI,寻址能力以及HTTP GET和POST的用法。


在某些浏览器中,链接预取会出现问题-即使页面作者未指示,它们也会调用预取链接。

,例如,您的注销位于“ GET”后面”链接到您网站上的每个页面,人们就可以由于这种行为而注销。

评论


许多很多工具,实用程序,Web爬网程序和其他东西都假定GET永远不会是破坏性的操作(正确的做法是,因为它是用这种方式指定的)。如果现在通过破坏该规范破坏应用程序,则将保留应用程序的两个部分。

–约阿希姆·绍尔(Joachim Sauer)
13年1月1日在12:21

@NimChimpsky:它确实会被GET更改。该建议完全是错误的。安全意味着用户不能对副作用负责,也不意味着不能有副作用。否则,您将没有服务器的日志文件,这很荒谬! RFC2616的9.1.1节非常清楚地阐明了这一点。

–Jörg W Mittag
2013年3月1日14:35

@JörgWMittag:我不会说“完全错误”,我会说“措词不完美”。 GET不应改变,这是它的目标。当然,您可以计数,记录和观察GET请求。但它不应修改您的实际业务数据。

–约阿希姆·绍尔(Joachim Sauer)
13年1月1日在14:54

@NimChimpsky GET不应更改GET请求的资源,但这并不意味着“服务器上的任何内容都不应更改”。当然,在任何请求期间,诸如日志,计数器和其他服务器状态之类的内容都可能发生变化。

–埃里克·金(Eric King)
13年1月1日14:55在

几年前,Google发布了一个浏览器插件(iirc),该插件可以通过链接预取页面。这也发生在某些设计不佳的控制面板上-URL将导致记录或某些内容在服务器上被写入甚至删除(请考虑post?action = delete)。这导致在用户不知道的情况下执行动作。 Google终止了该插件iirc的使用,即使这是Web应用程序制造商使用GET更改状态的错误。

–cthulhu
2013年3月1日15:41



#2 楼

每个HTTP动词都有自己的责任。例如,RFC定义的GET意味着检索Request-URI标识的任何信息(以实体形式)。


POST表示正式插入或更多


POST方法用于请求源服务器接受
作为请求的新下属包含在请求中的实体
,由请求行中的Request-URI标识



保持这种方式的原因:


它非常简单,自1991年以来就可以在全球Internet规模上运行。
坚持单一责任原则
其他各方​​使用GET作为信息检索和数据的手段挖掘
被认为是永远不会修改资源状态的安全操作
安全考虑,GET实际上是读操作,而POST实际上是写操作

GET是由浏览器,网络中的节点,Internet服务提供商缓存的
除非内容有所更改,否则对同一URL的GET必须向所有用户返回相同的结果,否则您将不会获得任何信任返回结果中的所有内容

为了完整性并强制执行正确的用法(源):



GET参数作为一部分传递网址,该网址的长度很小,默认限制为256个字符,某些服务器支持4000多个字符。如果要插入一个长期的记录,有传在
当使用安全连接,̶如TLS,̶网址没有得到加密,从而̶所有参数̶̶G̶E̶T̶̶此数据没有合法的途径̶t̶r̶a̶n̶s̶f̶e̶r̶r̶e̶d̶̶p̶l̶a̶i̶n̶̶t̶e̶x̶t̶。 URL实际上是使用TLS加密的,所以TLS很好。
使用GET插入二进制数据或非ASCII字符是不切实际的

如果用户在浏览器中按下“后退”按钮,则会重新执行GET
某些较早的爬网程序可能无法为其中带有?符号的URL编制索引


评论


您确定URL未通过TLS加密吗?我的印象是SSL / TLS握手发生在传输HTTP标头之前。这就是为什么很难在单个IP地址上虚拟托管HTTPS站点的原因。我错了吗

–布兰登
13年3月2日在17:17



是的,我已修复

–oleksii
13年3月2日在20:14

@Brandon Modern浏览器在TLS握手过程中以明文形式发送主机域(称为服务器名称指示),以允许每个IP地址托管多个域。网址的路径/查询部分受TLS保护。在这方面,GET和其他HTTP动词之间没有区别。

– CodesInChaos
13年3月2日在21:41

#3 楼

编辑:之前,我说过POST可以帮助您防御CSRF,但这是错误的。我不认为这是正确的。您必须在所有更改数据的请求中要求一个会话范围的唯一隐藏令牌,以防止CSRF攻击。

互联网诞生之初,出现了浏览器加速器。这些程序将开始单击页面上的链接以缓存内容。 Google Web Accelerator就是这些程序之一。这可能会对单击链接时进行更改的应用程序造成严重破坏。我假设仍然有人在使用加速器软件。

代理服务器和浏览器将缓存GET请求,因此当用户再次访问该页面时,它可能不会将请求发送到您的应用程序,因此用户认为他们采取了行动,但实际上没有采取行动。

评论


GET和POST同样可能实现CSRF。例如,攻击者可以在其站点上包括自动提交表单,以触发POST请求。防止CSRF的标准方法是在请求中明确包含攻击者不知道的值(与隐式包含cookie标头不同)。

– CodesInChaos
2015年12月28日在17:53



#4 楼


如果我做一个将数据插入数据库的php服务,并在GET查询字符串中传递
参数,那为什么会出错呢?


最简单答案是“因为那不是GET的意思”。

使用GET传递数据进行更新就像写一封情书并将其发送到标有“特价-立即行动!”的信封中一样。在这两种情况下,收件人和/或中介机构对您的邮件处理不当都不会感到惊讶。

评论


像这样的答案使该站点比其他站点更有价值/更具娱乐性。

– Killjoy
20-04-29在5:22

#5 楼

对于以数据库为中心的应用程序中的CRUD操作,请使用以下架构:

将HTTP GET用于读取操作(SQL SELECT)

将HTTP PUT用于更新操作(SQL UPDATE) )

使用HTTP POST进行创建操作(SQL INSERT)

使用HTTP DELETE进行删除操作(SQL DELETE)

评论


放置与发布不如您所说。当客户端在给定的确切位置修改资源时,放置权。对于发布,服务器最终决定资源的确切Uri。

–安迪
2014年3月20日在0:54

HTTP PUT是否更像SQL DELETE和INSERT而不是UPDATE?同样,SQL UPDATE可以一次更新许多记录,但是HTTP PUT仅更新一件事。

– David Klempfner
18年8月31日在1:39

PATCH用于更新

–GreenSaguaro
20年1月6日,19:35

#6 楼


GET永远不要更改服务器上的数据-使用POST请求



该建议,这里的所有答案都是错误的。显然,我过于戏剧化,其他答案也很好,但是我相信确切的建议应为:


GET很少更改服务器上的数据-使用POST要求



说“从不”太极端了,尽管这里的其他答案准确地解释了为什么您应该“很少”这样做,但是在某些情况下用GET更改数据是完全合理的。一个示例是一次性使用电子邮件验证链接。通常,这些链接包含一个GUID,在访问该GUID时必须更改数据。如果正确实现,则随后的相同GET请求将被忽略。

这显然是一个极端的情况,但肯定值得注意。

评论


如果您的邮件客户端决定在不单击链接的情况下获取链接,该怎么办?例如,因为它想对其进行扫描以查找恶意软件。取消订阅链接的正确方法是进入一个页面,用户可以单击该页面以取消订阅(单击按钮会触发POST请求)。

– CodesInChaos
15年12月28日在17:55

@CodesInChaos-非常好!我同意你的看法。我已经删除了取消订阅的示例,并留下了电子邮件验证作为唯一的示例。除电子邮件验证外,还有其他一些使GET有意义的方法,但目前我还没有想到。

– TTT
2015年12月28日在18:31



GET具有副作用的问题同样适用于电子邮件确认。现在,点击链接的客户将确认其他人使用您的电子邮件创建的帐户,从而允许他们模拟您。

– CodesInChaos
15年12月28日在18:35

@CodesInChaos-一个人。您所说的假冒来自相同的用户名或公用个人名称,而不是相同的电子邮件地址,并且无论使用什么电子邮件地址(通常只有服务器始终知道帐户持有人的电子邮件地址),这种冒名都会发生。此外,用他人的电子邮件地址创建一个帐户是没有意义的。那对他们有什么帮助?他们无法控制自己的帐户。

– TTT
15/12/28在19:18