为什么在删除时应该使用HTTP POST或DELETE而不是GET?

43
我一直在学习微软的ASP.NET MVC教程,最终到达了这个页面: http://www.asp.net/learn/mvc/tutorial-32-cs.aspx 该页面底部给出了以下声明: “通常情况下,当调用修改Web应用程序状态的操作时,您不希望执行HTTP GET操作。执行删除操作时,您要执行HTTP POST操作,或者更好的做法是执行HTTP DELETE操作。” 这是真的吗?有人可以提供更详细的解释来支持这种说法吗?

编辑

维基百科 上这样说: “一些方法(例如HEAD、GET、OPTIONS和TRACE)被定义为安全的,这意味着它们仅用于信息检索,不应改变服务器状态。 相比之下,POST、PUT和DELETE等方法旨在执行可能在服务器上引起副作用的操作。”
10个回答

70

Jon Skeet的回答是经典答案。但是:假设你有一个链接:

href = "\myApp\DeleteImportantData.aspx?UserID=27"

那如果 Google 爬虫访问并索引了你的页面,会发生什么呢?


这被称为跨站点请求伪造漏洞。 - Gumbo
1
不一定。看看Marc Gravell发布的链接(毁灭之蜘蛛)。我读过几篇描述这种问题的文章,通常是在JavaScript验证后面,而蜘蛛会忽略它。是的,它可能是恶意的,但大多数时候只是愚蠢。 - Chris Cudmore
17
蜘蛛不是问题,身份验证可以解决这个问题。一个更现实的问题是 <img src="DeleteImportantData.aspx?UserID=27"> 这种东西。 - user247702

55

GET通常没有副作用,换句话说,它不会改变状态。这意味着结果可以被缓存,书签可以安全地创建等。

来自HTTP 1.1 RFC 2616

实现者应该意识到,软件代表用户在他们与互联网的交互中,并且应该小心允许用户了解他们可能采取的任何行动,这些行动可能对他们自己或他人具有意外的重要性。

特别是,已经建立了GET和HEAD方法不应具有除检索之外的其他意义的约定。这些方法应该被认为是“安全”的。这允许用户代理以特殊方式表示其他方法,例如POST、PUT和DELETE,以便告知用户正在请求可能不安全的操作。

当然,无法确保服务器不会在执行GET请求的结果上产生副作用;事实上,一些动态资源认为这是一个功能。这里的重要区别是用户没有请求副作用,因此不能对其负责。


2
我的理解是幂等操作可以改变状态,但多次应用幂等操作与单次应用具有相同的结果。例如,HTTP DELETE是幂等的,但HTTP POST不是。GETHEAD除了幂等性之外还有一个额外的约定,即即使在初始应用中也不会产生副作用。请参阅http://stephenwalther.com/archive/2009/01/21/asp-net-mvc-tip-46-ndash-donrsquot-use-delete-links-because.aspx。 - Matthew

21
除了关于幂等性的纯粹问题外,还有一个实用的方面:蜘蛛/机器人/爬虫等会遵循超链接。如果您将“删除”操作设置为执行GET的超链接,则谷歌可以愉快地删除所有数据。请参见“毁灭之蜘蛛”。
对于帖子,这不是一个风险。

18

另一个例子...

http://example.com/admin/articles/delete/2
如果您已登录并具有适当的权限,则此操作将删除文章。比如,如果您的网站允许评论,并且用户将该链接作为图片提交,那么它会像这样:
<img src="http://example.com/admin/articles/delete/2" alt="This will delete your article."/>

当您作为管理员用户浏览站点上的评论时,浏览器将尝试通过发送到该URL的请求来获取该图像。但因为在浏览器执行此操作时您已登录,所以文章将被删除。

如果浏览器找不到图像,大多数浏览器不会显示任何内容,所以您可能甚至没有注意到。

希望这样能让您理解。


很棒的答案!以管理员身份浏览是一个不错的思路。 - Siddhartha

12

请参见我的答案。它同样适用于这个问题。

  • 预取: 很多网络浏览器会使用预取,也就是在你点击链接之前加载页面,预期你稍后会点击该链接。
  • 机器人: 有几种机器人会扫描和索引互联网上的信息,它们只会发出GET请求。因此,出于这个原因,您不应该从GET请求中删除任何内容。
  • 缓存: GET HTTP请求不应更改状态,并且应该是幂等的。幂等意味着发出一次请求或多次请求都会产生相同的结果。即没有副作用。因此,GET HTTP请求与缓存紧密相关。
  • HTTP标准如此规定: HTTP标准规定了每个HTTP方法的用途。有几个程序是基于HTTP标准构建的,它们假设您将按照规定使用它。因此,如果您不遵循规定,将会对大量随机程序产生未定义的行为。

4
除了蜘蛛和请求必须是幂等的之外,GET请求还存在安全问题。有人可以轻易地向您的用户发送电子邮件内容为:
<img src="http://yoursite/Delete/Me" />

在文本中使用POST方法,浏览器将愉快地尝试访问资源。使用POST方法并不能完全解决这类问题(因为您可以很容易地在JavaScript中构建表单提交),但这是一个不错的开始。

3
除了这里提到的所有优点外,GET请求可以被接收方服务器记录在access.log中。如果您在请求中发送敏感数据,例如密码,它们将作为明文记录下来。
即使它们被哈希/盐值化用于安全的数据库存储,一次违规行为(或有人正在IT人员的肩膀后面窥视)就可能揭示出它们。这种数据应该放在POST正文中。

3

3
链接唯一的答案中有损坏的链接 :-( - Duncan Jones

2
假设我们有一个网银应用程序,我们访问转账页面。登录用户选择向另一个帐户转账10美元。
点击提交按钮后(作为GET请求)重定向到https://my.bank.com/users/transfer?amount=10&destination=23lk3j2kj31lk2j3k2j
但是,因为互联网连接较慢和/或服务器繁忙,所以在点击提交按钮后,新页面加载很慢。
用户感到沮丧,开始疯狂地按F5(刷新页面)。你猜会发生什么?可能会发生多次转账,甚至会清空用户的帐户。
现在,如果请求是以POST方式(或者不是以GET方式),用户在第一次按下F5(刷新页面)时,浏览器会友好地询问:“你确定要这样做吗?它可能会产生副作用 [ bla bla bla ] ... ”。

1
我的银行在他们的移动应用程序上做到了这一点!太疯狂了! - calcazar
1
请告诉我这是个玩笑。 - Andrei Rînea
1
不是笑话!不良实践是一种痛苦,已经让我付出了数次透支费用。 - calcazar
这真的很伤心 :( - Andrei Rînea

1

使用 GET 方法的另一个问题是该命令会出现在浏览器的地址栏中。因此,如果您刷新页面,就会再次发出该命令,无论是“删除上一条记录”、“提交订单”或其他类似的命令。


这是不正确的。使用POST也有同样的问题。人们使用“POST-重定向-获取”方法。 - eu-ge-ne
1
我不知道其他浏览器,但至少在Firefox中,如果我刷新一个页面(或返回到发送POST请求后到达的页面),它至少会警告我并询问我是否要重新发送请求。而对于GET请求,你没有任何警告! - PhiLho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接