1. 程式人生 > >http的安全方法和冪等性

http的安全方法和冪等性

基於HTTP協議的Web API是時下最為流行的一種分散式服務提供方式。無論是在大型網際網路應用還是企業級架構中,我們都見到了越來越多的SOA或RESTful的Web API。為什麼Web API如此流行呢?我認為很大程度上應歸功於簡單有效的HTTP協議。HTTP協議是一種分散式的面向資源的網路應用層協議,無論是伺服器端提供Web服務,還是客戶端消費Web服務都非常簡單。再加上瀏覽器、Javascript、AJAX、JSON以及HTML5等技術和工具的發展,網際網路應用架構設計表現出了從傳統的PHP、JSP、ASP.NET等伺服器端動態網頁向Web API + RIA(富網際網路應用)過渡的趨勢。Web API專注於提供業務服務,RIA專注於使用者介面和互動設計,從此兩個領域的分工更加明晰。在這種趨勢下,Web API設計將成為伺服器端程式設計師的必修課。然而,正如簡單的Java語言並不意味著高質量的Java程式,簡單的HTTP協議也不意味著高質量的Web API。要想設計出高質量的Web API,還需要深入理解分散式系統及HTTP協議的特性。

冪等性定義

本文所要探討的正是HTTP協議涉及到的一種重要性質:冪等性(Idempotence)。在HTTP/1.1規範中冪等性的定義是:

Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.

從定義上看,HTTP方法的冪等性是指一次和多次請求某一個資源應該具有同樣的副作用。冪等性屬於語義範疇,正如編譯器只能幫助檢查語法錯誤一樣,HTTP規範也沒有辦法通過訊息格式等語法手段來定義它,這可能是它不太受到重視的原因之一。但實際上,冪等性是分散式系統設計中十分重要的概念,而HTTP的分散式本質也決定了它在HTTP中具有重要地位。

分散式事務 vs 冪等設計

為什麼需要冪等性呢?我們先從一個例子說起,假設有一個從賬戶取錢的遠端API(可以是HTTP的,也可以不是),我們暫時用類函式的方式記為:

bool withdraw(account_id, amount)

withdraw的語義是從account_id對應的賬戶中扣除amount數額的錢;如果扣除成功則返回true,賬戶餘額減少amount;如果扣除失敗則返回false,賬戶餘額不變。值得注意的是:和本地環境相比,我們不能輕易假設分散式環境的可靠性。一種典型的情況是withdraw請求已經被伺服器端正確處理,但伺服器端的返回結果由於網路等原因被掉丟了,導致客戶端無法得知處理結果。如果是在網頁上,一些不恰當的設計可能會使使用者認為上一次操作失敗了,然後重新整理頁面,這就導致了withdraw被呼叫兩次,賬戶也被多扣了一次錢。如圖1所示:

non-idempotent

圖1

這個問題的解決方案一是採用分散式事務,通過引入支援分散式事務的中介軟體來保證withdraw功能的事務性。分散式事務的優點是對於呼叫者很簡單,複雜性都交給了中介軟體來管理。缺點則是一方面架構太重量級,容易被綁在特定的中介軟體上,不利於異構系統的整合;另一方面分散式事務雖然能保證事務的ACID性質,而但卻無法提供效能和可用性的保證。

另一種更輕量級的解決方案是冪等設計。我們可以通過一些技巧把withdraw變成冪等的,比如:

int create_ticket() 
bool idempotent_withdraw(ticket_id, account_id, amount)

create_ticket的語義是獲取一個伺服器端生成的唯一的處理號ticket_id,它將用於標識後續的操作。idempotent_withdraw和withdraw的區別在於關聯了一個ticket_id,一個ticket_id表示的操作至多隻會被處理一次,每次呼叫都將返回第一次呼叫時的處理結果。這樣,idempotent_withdraw就符合冪等性了,客戶端就可以放心地多次呼叫。

基於冪等性的解決方案中一個完整的取錢流程被分解成了兩個步驟:1.呼叫create_ticket()獲取ticket_id;2.呼叫idempotent_withdraw(ticket_id, account_id, amount)。雖然create_ticket不是冪等的,但在這種設計下,它對系統狀態的影響可以忽略,加上idempotent_withdraw是冪等的,所以任何一步由於網路等原因失敗或超時,客戶端都可以重試,直到獲得結果。如圖2所示:

idempotent

圖2

和分散式事務相比,冪等設計的優勢在於它的輕量級,容易適應異構環境,以及效能和可用性方面。在某些效能要求比較高的應用,冪等設計往往是唯一的選擇。

HTTP的冪等性

HTTP協議本身是一種面向資源的應用層協議,但對HTTP協議的使用實際上存在著兩種不同的方式:一種是RESTful的,它把HTTP當成應用層協議,比較忠實地遵守了HTTP協議的各種規定;另一種是SOA的,它並沒有完全把HTTP當成應用層協議,而是把HTTP協議作為了傳輸層協議,然後在HTTP之上建立了自己的應用層協議。本文所討論的HTTP冪等性主要針對RESTful風格的,不過正如上一節所看到的那樣,冪等性並不屬於特定的協議,它是分散式系統的一種特性;所以,不論是SOA還是RESTful的Web API設計都應該考慮冪等性。下面將介紹HTTP GET、DELETE、PUT、POST四種主要方法的語義和冪等性。

HTTP GET方法用於獲取資源,不應有副作用,所以是冪等的。比如:GET http://www.bank.com/account/123456,不會改變資源的狀態,不論呼叫一次還是N次都沒有副作用。請注意,這裡強調的是一次和N次具有相同的副作用,而不是每次GET的結果相同。GET http://www.news.com/latest-news這個HTTP請求可能會每次得到不同的結果,但它本身並沒有產生任何副作用,因而是滿足冪等性的。

HTTP DELETE方法用於刪除資源,有副作用,但它應該滿足冪等性。比如:DELETE http://www.forum.com/article/4231,呼叫一次和N次對系統產生的副作用是相同的,即刪掉id為4231的帖子;因此,呼叫者可以多次呼叫或重新整理頁面而不必擔心引起錯誤。

比較容易混淆的是HTTP POST和PUT。POST和PUT的區別容易被簡單地誤認為“POST表示建立資源,PUT表示更新資源”;而實際上,二者均可用於建立資源,更為本質的差別是在冪等性方面。在HTTP規範中對POST和PUT是這樣定義的:

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line ...... If a resource has been created on the origin server, the response SHOULD be 201 (Created) and contain an entity which describes the status of the request and refers to the new resource, and a Location header.

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.

POST所對應的URI並非建立的資源本身,而是資源的接收者。比如:POST http://www.forum.com/articles的語義是在http://www.forum.com/articles下建立一篇帖子,HTTP響應中應包含帖子的建立狀態以及帖子的URI。兩次相同的POST請求會在伺服器端建立兩份資源,它們具有不同的URI;所以,POST方法不具備冪等性。而PUT所對應的URI是要建立或更新的資源本身。比如:PUT http://www.forum/articles/4231的語義是建立或更新ID為4231的帖子。對同一URI進行多次PUT的副作用和一次PUT是相同的;因此,PUT方法具有冪等性。

在介紹了幾種操作的語義和冪等性之後,我們來看看如何通過Web API的形式實現前面所提到的取款功能。很簡單,用POST /tickets來實現create_ticket;用PUT /accounts/account_id/ticket_id&amount=xxx來實現idempotent_withdraw。值得注意的是嚴格來講amount引數不應該作為URI的一部分,真正的URI應該是/accounts/account_id/ticket_id,而amount應該放在請求的body中。這種模式可以應用於很多場合,比如:論壇網站中防止意外的重複發帖。

總結

上面簡單介紹了冪等性的概念,用冪等設計取代分散式事務的方法,以及HTTP主要方法的語義和冪等性特徵。其實,如果要追根溯源,冪等性是數學中的一個概念,表達的是N次變換與1次變換的結果相同,有興趣的讀者可以從Wikipedia上進一步瞭解。

參考

安全操作,冪等操作 

google了一些中文的資料, 基本瞭解了冪等是怎麼回事兒. 備忘一下. 
PUT,DELETE操作是冪等的。所謂冪等是指不管進行多少次操作,結果都一樣。比如我用PUT修改一篇文章,然後在做同樣的操作,每次操作後的結果並沒有不同,DELETE也是一樣。順便說一句,因為GET操作是安全的,所以它自然也是冪等的。 


POST操作既不是安全的,也不是冪等的,比如常見的POST重複載入問題:當我們多次發出同樣的POST請求後,其結果是創建出了若干的資源。 


安全和冪等的意義在於:當操作沒有達到預期的目標時,我們可以不停的重試,而不會對資源產生副作用。從這個意義上說,POST操作往往是有害的,但很多時候我們還是不得不使用它。 


還有一點需要注意的就是,建立操作可以使用POST,也可以使用PUT,區別在於POST是作用在一個集合資源之上的(/articles),而PUT操作是作用在一個具體資源之上的(/articles/123),再通俗點說,如果URL可以在客戶端確定,那麼就使用PUT,如果是在服務端確定,那麼就使用POST,比如說很多資源使用資料庫自增主鍵作為標識資訊,而建立的資源的標識資訊到底是什麼只能由服務端提供,這個時候就必須使用POST。 


一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。冪等操作對於代理和快取來說具有“友好性”,因為冪等操作的額外執行不會對二者產生危害性後果(除了頻寬浪費)。 
PUT方法是冪等的,冪等性意味著對於一個成功執行的請求,不管其執行多少次,其結果都是一致的。也就是說,只要你願意,你可以用PUT方法對 Hotel資源進行任意次更新,其結果都一樣。如果兩個PUT方法同時發生,那麼只有其中之一會贏得最後的勝利並決定資源的最終狀態。刪除操作也是冪等的,如果一個PUT方法和DELETE方法同時發生,那麼資源或者被更新,或者被刪除,而不可能停留在某個中間狀態。 


如果你不確定是PUT還是DELETE被成功執行,並且沒有得到狀態碼409 (Conflict)或者 417 (Expectation Failed)的話,那麼就重新執行一遍。而不需要附加的可靠性協議來避免重複請求,因為通常重複的請求不會有任何影響。 


上述描述對於POST方法就不適用了,因為POST方法不是冪等的,若要兩次執行同一個POST請求那就要注意了。POST方法所缺失的冪等性就解釋了為什麼當你每次重新發送POST請求時瀏覽器總是彈出警告。POST方法用於建立資源,而不需要由客戶端指定例項id 


冪等函式,或冪等方法,是指可以使用相同引數重複執行,並能獲得相同結果的函式。這些函式不會影響系統狀態,也不用擔心重複執行會對系統造成改變。例如,“getUsername()”函式就是一個冪等函式,“deleteFile()”函式就不是。“冪等”是HTTP Session和EJB失敗轉移中的一個重要概念。 
當正在進行方法呼叫的時候失敗了怎麼辦呢?答案是:處理過程中止,客戶端看見錯誤訊息提示(除非方法是冪等方法)。只有方法是冪等方法的情況,一些負載均衡器才能試圖失敗轉移這些方法到別的例項。 


冪等為何如此重要?因為客戶端並不知道伺服器何時失敗的(在方法剛開始呼叫或者快要呼叫完成的時候)。如果是非冪等方法,則兩次呼叫就會兩次改變系統狀態,系統就會處於不一致的狀態。 


在複雜應用中,不太可能把所有的方法都變成冪等方法。所以,只能通過失敗轉移減少錯誤,而不可能從根本上避免錯誤。 


把應用程式設計為冪等的:冪等的的意思就是一個操做不會修改狀態資訊,並且每次操作的時候都返回同樣的結果(換句話說就是:做多次和做一次的效果是一樣的),通常,WEB請求,特別是 HTML forms 都被髮送多次(當用戶點擊發送按紐兩次,過載頁面多次),導致多次HTTP請求。設計SERVLET和其他WEB物件為 冪等的,可以容忍多次請求。詳細可以去參考設計模式“Synchronized Token ”和“Idempotent Receiver ”關於怎樣設計冪等的的應用程式。

相關推薦

http安全方法

基於HTTP協議的Web API是時下最為流行的一種分散式服務提供方式。無論是在大型網際網路應用還是企業級架構中,我們都見到了越來越多的SOA或RESTful的Web API。為什麼Web API如此流行呢?我認為很大程度上應歸功於簡單有效的HTTP協議。HTTP協議是一種分散式的面向資源的網路應用層協議,

HTTP請求方法探究(是重點)

一、HTTP請求方法 根據HTTP標準,HTTP請求可以使用多種請求方式。GET POST HEAD OPTIONS PUT PATCH DELETE TRACE CONNECT。 index method description 1 GET

HttpHTTP方法的安全性

Http協議規定了不同方法的安全特性和冪等特性,作為服務提供者的伺服器必需為客戶端提供這些特性。 安全性 僅指方法的多次呼叫不會產生副作用,不涉及傳統意義上的“安全”,這裡的副作用是指資源狀態。即,安全的方法不會修改資源狀態,儘管多次呼叫的返回值可能不一樣(被其

使用ASP.NET Core 3.x 構建 RESTful API - 4.3 HTTP 方法的安全性

什麼樣的HTTP方法是安全的?  如果一個方法不會改變資源的表述,那麼這個方法就被認為是安全的。  例如 HTTP GET 和 HTTP HEAD 就被認為是安全的,但需要注意的是,這並不意味著執行GET請求就不會引起其它的資

分布式系統(微服務架構)的一致性問題相關概念解析

數據復制 ref cap 發送 答案 一次 重復值 聯系 現實 目錄 前言 1. 分布式系統的數據一致性 1.1 分布式存儲系統中的一致性問題 1.2 微服務應用的分布式一致性問題 1.3 對於一致性的正確理解 2.分布式一致性模型 3. 追求強一致性的約束——CAP定

分散式系統(微服務架構)的一致性問題相關概念解析

分散式系統(微服務架構)的一致性和冪等性問題相關概念解析 目錄 前言 1. 分散式系統的資料一致性 1.1 分散式儲存系統中的一致性問題 1.2 微服務應用的分散式一致性問題 1.3 對於一致性的正確理解 2.分散式一致性模型

如何保證訊息佇列的高可用以及資料丟失,順序一致性

如何保證訊息佇列的高可用和冪等性以及資料丟失,順序一致性 <!-- more --> RabbitMQ的高可用性 RabbitMQ是比較有代表性的,因為是基於主從做高可用性的,我們就以他為例子講解第一種MQ的高可用性怎麼實現。 rabbitmq有三種模式: 單機模式 普通叢集模

理解HTTP

重要性 動態網頁 true http post rom 放心 業務 定義 rop FROM http://www.cnblogs.com/weidagang2046/archive/2011/06/04/idempotence.html 基於HTTP協議的Web A

理解http

比較 第一次 接收 出現問題 做到 的區別 重復提交 都沒有 在操作 冪等性是什麽? 冪等性——是系統的接口對外一種承諾(而不是實現),承諾只要調用接口成功,外部多次調用對系統的影響是一致的。一個冪等的操作典型如:把編號為5的記錄的A字段設置為0,這種操作不管執行多少次都是

程式設計中的HTTP

冪等(idempotent、idempotence)是一個數學與計算機學概念,常見於抽象代數中。 在程式設計中.一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。冪等函式,或冪等方法,是指可以使用相同引數重複執行,並能獲得相同結果的函式。這些函式不會影響系統狀態,也不用擔心重

HTTP及GET、POST、PUT、DELETE的區別

基於HTTP協議的Web API是時下最為流行的一種分散式服務提供方式。無論是在大型網際網路應用還是企業級架構中,我們都見到了越來越多的SOA或RESTful的Web API。為什麼Web API如此流行呢?我認為很大程度上應歸功於簡單有效的HTTP協議。HTTP協議是一種分散式的面向資源的網路應用層協議,

iOS 學習 RESTful 中 Http

一. RESTful    RESTful (Representational State Transfer) 是一種常用流行的軟體架構,設計風格或協議標準。提供了一組設計風格和約束條件。主要用於客戶端和服務端的互動。  1. 統一資源介面  2.使用http方法

ASP.NET WebApi服務介面如何防止重複請求實現HTTP(八)

一、背景描述與課程介紹 明人不說暗話,跟著阿笨一起玩WebApi。在我們平時開發專案中可能會出現下面這些情況; 1)、由於使用者誤操作,多次點選網頁表單提交按鈕。由於網速等原因造成頁面卡頓,使用者重複重新整理提交頁面。黑客或惡意使用者使用postman等工具重複惡意提交表單(攻擊網站)。這些情況都會導

程式設計中的(一):http

一、什麼是冪等性?什麼是冪等操作?冪等:是一個數學概念,表示N次變換和1次變換的結果相同。冪等操作:其特點是任意多次執行所產生的影響均與一次執行的影響相同(不會改變資源狀態,對資料沒有副作用)。冪等性:一系列操作都是冪等操作。冪等介面:冪等介面認為,外部呼叫者會存在多次呼叫的

理解解決方案

基於HTTP協議的Web API是時下最為流行的一種分散式服務提供方式。無論是在大型網際網路應用還是企業級架構中,我們都見到了越來越多的SOA或RESTful的Web API。為什麼Web API如此流行呢?我認為很大程度上應歸功於簡單有效的HTTP協議。HTTP協議是一種分散式的面向資源的網路應用層協議,

編程中的 —— HTTP

hdr 設計 same The 調用 不同 tick 表單 http 冪等(idempotent、idempotence)是一個數學與計算機學概念,常見於抽象代數中。 在編程中.一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。冪等函數,或冪等方法

Kafka筆記—可靠性、事務

這幾天很忙,但是我現在給我的要求是一週至少要出一篇文章,所以先拿這篇筆記來做開胃菜,原始碼分析估計明後兩天應該能寫一篇。給自己加油~,即使沒什麼人看。 可靠性 如何保證訊息不丟失 Kafka只對“已提交”的訊息(committed message)做有限度的持久化保證。 已提交的訊息 當Kafka的若干個Br

什麽是分布式系統中的

數據操作 返回 另一個 tid 訂單 增加 簡單的 事務 既然 最近很多人都在談論冪等性,好吧,這回我也來聊聊這個話題,光看著倆字,一開始的確有點一頭霧水,語文不好嘛,詞太專業嘛,對吧 現如今我們的系統大多拆分為分布式SOA,或者微服務,一套系統中包含了多個子系統服務,

分布式系統互斥問題的分析與解決

解決沖突 ldr 隊列 reads failure 是的 最大 循環鏈表 成員變量 前言 隨著互聯網信息技術的飛速發展,數據量不斷增大,業務邏輯也日趨復雜,對系統的高並發訪問、海量數據處理的場景也越來越多。如何用較低成本實現系統的高可用、易伸縮、可擴展等目標就顯得越發重要。

何謂

服務 post put delete 會有 結果 但是 請求 數據 對同一個資源,不管請求多少次,結果都是一樣的。 如在resful接口中, get 、delete,put ,請求 1次與n次,結果都是相等的。 而對於post ,每次都是新增一條數據,則不符合冪等性,但是可