当比较HTTP GET和HTTP POST时,从安全角度看有什么不同?其中一个选择是否天生就比另一个更安全?如果有,为什么?

我意识到POST没有公开URL上的信息,但其中有任何真正的价值吗?或者它只是通过隐匿性来实现安全?当安全性是一个问题时,我是否有理由更喜欢POST ?

编辑: 通过HTTPS, POST数据被编码,但url会被第三方嗅探吗?此外,我正在处理JSP;当使用JSP或类似的框架时,是否可以公平地说,最佳实践是避免将敏感数据完全放在POST或GET中,而是使用服务器端代码来处理敏感信息?


当前回答

除非使用https,否则不存在安全性—使用https, GET和POST之间的传输安全性是相同的。

但是一个重要的方面是客户机和服务器在记住请求时的区别。在考虑使用GET或POST进行登录时,要记住这一点非常重要。

使用POST,密码由服务器应用程序处理,然后丢弃,因为一个好的设计不会在数据库中存储密码——只存储加密安全的散列。

但是使用GET,服务器日志最终将包含包含查询参数的请求。因此,无论数据库中的密码哈希值有多好,服务器日志仍然会以明文形式包含密码。除非对文件系统进行加密,否则即使在删除日志文件之后,服务器磁盘仍将包含这些密码。

使用访问令牌作为查询参数时也会出现同样的问题。这也是为什么考虑在HTTP报头数据中提供任何访问令牌是有意义的原因——比如在授权报头中使用承载令牌。

服务器日志通常是web服务中最薄弱的部分,允许攻击者从泄露的信息中提升他们的访问权限。

其他回答

考虑一下这种情况:一个草率的API接受如下GET请求:

http://www.example.com/api?apikey=abcdef123456&action=deleteCategory&id=1

在某些设置中,当您请求此URL时,如果有关于请求的错误/警告,则整行内容将记录在日志文件中。更糟糕的是:如果您忘记禁用生产服务器中的错误消息,则此信息将在浏览器中显示!现在你已经把你的API密钥给了所有人。

不幸的是,有一些真正的API是这样工作的。

我不喜欢在日志中有一些敏感信息或在浏览器中显示它们的想法。POST和GET是不同的。在适当的地方使用它们。

GET对任何人都是可见的(甚至是你肩膀上的人),并且保存在缓存中,所以使用post不太安全,顺便说一句,没有一些加密程序的post是不确定的,为了一点安全性,你必须使用SSL (https)

由于通过HTTP POST发送的变量比通过HTTP GET发送的变量更安全,因此没有提供更高的安全性。

HTTP/1.1为我们提供了一系列发送请求的方法:

选项 得到 头 帖子 把 删除 跟踪 连接

让我们假设你有以下HTML文档使用GET:

<html>
<body>
<form action="http://example.com" method="get">
    User: <input type="text" name="username" /><br/>
    Password: <input type="password" name="password" /><br/>
    <input type="hidden" name="extra" value="lolcatz" />
    <input type="submit"/>
</form>
</body>
</html>

你的浏览器会问什么?它问的是:

 GET /?username=swordfish&password=hunter2&extra=lolcatz HTTP/1.1
 Host: example.com
 Connection: keep-alive
 Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/ [...truncated]
 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) [...truncated]
 Accept-Encoding: gzip,deflate,sdch
 Accept-Language: en-US,en;q=0.8
 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

现在让我们假设我们将请求方法更改为POST:

 POST / HTTP/1.1
 Host: example.com
 Connection: keep-alive
 Content-Length: 49
 Cache-Control: max-age=0
 Origin: null
 Content-Type: application/x-www-form-urlencoded
 Accept: application/xml,application/xhtml+xml,text/ [...truncated]
 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; [...truncated]
 Accept-Encoding: gzip,deflate,sdch
 Accept-Language: en-US,en;q=0.8
 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

 username=swordfish&password=hunter2&extra=lolcatz

这两个HTTP请求都是:

不加密的 包括在两个例子中 可以被偷取,并受到MITM攻击。 很容易被第三方复制,和脚本机器人。

许多浏览器不支持POST/GET以外的HTTP方法。

许多浏览器行为存储页面地址,但这并不意味着您可以忽略任何其他问题。

具体来说:

一种天生就比另一种更安全吗?我意识到POST不会暴露URL上的信息,但其中是否有任何真正的价值,或者它只是通过隐匿性来安全?这里的最佳实践是什么?

This is correct, because the software you're using to speak HTTP tends to store the request variables with one method but not another only prevents someone from looking at your browser history or some other naive attack from a 10 year old who thinks they understand h4x0r1ng, or scripts that check your history store. If you have a script that can check your history store, you could just as easily have one that checks your network traffic, so this entire security through obscurity is only providing obscurity to script kiddies and jealous girlfriends.

在https上,POST数据被编码,但url可能被第三方嗅探?

下面是SSL的工作原理。还记得我上面发送的两个请求吗?下面是它们在SSL中的样子: (我将页面更改为https://encrypted.google.com/,因为example.com在SSL上没有响应)。

通过SSL POST

q5XQP%RWCd2u#o/T9oiOyR2_YO?yo/3#tR_G7 2_RO8w?FoaObi)
oXpB_y?oO4q?`2o?O4G5D12Aovo?C@?/P/oOEQC5v?vai /%0Odo
QVw#6eoGXBF_o?/u0_F!_1a0A?Q b%TFyS@Or1SR/O/o/_@5o&_o
9q1/?q$7yOAXOD5sc$H`BECo1w/`4?)f!%geOOF/!/#Of_f&AEI#
yvv/wu_b5?/o d9O?VOVOFHwRO/pO/OSv_/8/9o6b0FGOH61O?ti
/i7b?!_o8u%RS/Doai%/Be/d4$0sv_%YD2_/EOAO/C?vv/%X!T?R
_o_2yoBP)orw7H_yQsXOhoVUo49itare#cA?/c)I7R?YCsg ??c'
(_!(0u)o4eIis/S8Oo8_BDueC?1uUO%ooOI_o8WaoO/ x?B?oO@&
Pw?os9Od!c?/$3bWWeIrd_?( `P_C?7_g5O(ob(go?&/ooRxR'u/
T/yO3dS&??hIOB/?/OI?$oH2_?c_?OsD//0/_s%r

通过SSL

rV/O8ow1pc`?058/8OS_Qy/$7oSsU'qoo#vCbOO`vt?yFo_?EYif)
43`I/WOP_8oH0%3OqP_h/cBO&24?'?o_4`scooPSOVWYSV?H?pV!i
?78cU!_b5h'/b2coWD?/43Tu?153pI/9?R8!_Od"(//O_a#t8x?__
bb3D?05Dh/PrS6_/&5p@V f $)/xvxfgO'q@y&e&S0rB3D/Y_/fO?
_'woRbOV?_!yxSOdwo1G1?8d_p?4fo81VS3sAOvO/Db/br)f4fOxt
_Qs3EO/?2O/TOo_8p82FOt/hO?X_P3o"OVQO_?Ww_dr"'DxHwo//P
oEfGtt/_o)5RgoGqui&AXEq/oXv&//?%/6_?/x_OTgOEE%v (u(?/
t7DX1O8oD?fVObiooi'8)so?o??`o"FyVOByY_ Supo? /'i?Oi"4
tr'9/o_7too7q?c2Pv

(注意:我将HEX转换为ASCII,其中一些显然是不可显示的)

整个HTTP会话都是加密的,通信的唯一可见部分是在TCP/IP层(即IP地址和连接端口信息)。

让我在这里做一个大胆的声明。你的网站并没有通过一种HTTP方法提供比另一种更大的安全性,世界各地的黑客和新手都确切地知道如何做我刚才在这里演示的事情。如果需要安全性,请使用SSL。浏览器倾向于存储历史,RFC2616 9.1.1建议不要使用GET来执行操作,但认为POST提供了安全性是完全错误的。

POST的唯一安全措施是什么?防止嫉妒的前任翻看你的浏览记录。就是这样。全世界的人都登录了你的账户嘲笑你。

为了进一步证明为什么POST不安全,Facebook到处都在使用POST请求,那么像FireSheep这样的软件是如何存在的呢?

Note that you may be attacked with CSRF even if you use HTTPS and your site does not contain XSS vulnerabilities. In short, this attack scenario assumes that the victim (the user of your site or service) is already logged in and has a proper cookie and then the victim's browser is requested to do something with your (supposedly secure) site. If you do not have protection against CSRF the attacker can still execute actions with the victims credentials. The attacker cannot see the server response because it will be transferred to the victim's browser but the damage is usually already done at that point.

Neither one of GET and POST is inherently "more secure" than the other, just like neither one of fax and phone is "more secure" than the other. The various HTTP methods are provided so that you can choose the one which is most appropiate for the problem you're trying to solve. GET is more appropiate for idempotent queries while POST is more appropiate for "action" queries, but you can shoot yourself in the foot just as easily with any of them if you don't understand the security architecture for the application you're maintaining.

最好是阅读第9章:HTTP/1.1 RFC的方法定义,以全面了解get和POST最初的含义。

我不打算重复所有其他的答案,但有一个方面我还没有看到提到——那就是数据消失的故事。我不知道去哪里找,但是…

基本上,它是关于一个网络应用程序,每隔几晚就会神秘地丢失所有数据,而且没有人知道原因。检查日志后发现,该网站是由谷歌或其他任意蜘蛛找到的,它很高兴地GET(读:GET)它在网站上找到的所有链接——包括“删除此条目”和“你确定吗?”链接。

事实上,部分已经提到了。这就是“不要在GET上而只在POST上更改数据”背后的故事。爬虫会很高兴地遵循GET,而不是POST。即使robots.txt也不能帮助对抗行为不当的爬虫。