GET永远不要更改服务器上的数据-为此使用POST请求
这个想法的基础是什么?
如果我提供了将数据插入数据库并在GET查询字符串中传递参数的php服务,那为什么会出错呢? (我正在使用准备好的语句来处理SQL注入)。 POST请求在某种程度上更安全吗?
还是有历史原因?如果是这样的话,今天的建议是否有效?
#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
评论
有一个相关的DailyWTF条目。命令/查询分离。
感谢您提出这个问题,也感谢@Oded的口头表达,我一直都需要参考,以将提出这个问题的人发送给:)
另请参阅HTTP PUT-stackoverflow.com/questions/630453/put-vs-post-in-rest(带有关于幂等的注释)
@JoachimSauer尽管GET会将它们从爬网程序中保存下来,但根本的问题是缺少身份验证。任何脚本小子也可以将其过时。