1. 程式人生 > >api介面對於客戶端的身份認證方式以及安全措施 基於http協議的api介面對於客戶端的身份認證方式以及安全措施

api介面對於客戶端的身份認證方式以及安全措施 基於http協議的api介面對於客戶端的身份認證方式以及安全措施

轉載

基於http協議的api介面對於客戶端的身份認證方式以及安全措施

 由於http是無狀態的,所以正常情況下在瀏覽器瀏覽網頁,伺服器都是通過訪問者的cookie(cookie中儲存的jsessionid)來辨別客戶端的身份的,當客戶端進行登入伺服器也會將登入資訊存放在伺服器並與客戶端的cookie中的jsessionid關聯起來,這樣客戶端再次訪問我們就可以識別使用者身份了。

    但是對於api伺服器,我們不能讓訪問者先登入再進行訪問這樣不安全,也不友好。所以一般情況我們都是需要客戶端提供一個key(每個key跟使用者是一對一關聯的)來識別請求者的身份。

    由HTTP協議進行通訊的資料大都是未經加密的明文,包括請求引數、返回值、 cookie、 head等等資料,因此,外界通過對通訊的監聽,輕而易舉便可根據請求和響應雙方的格式,偽造請求與響應,修改和竊取各種資訊。所以我們還需要對每次請求進行認證,來判斷髮起請求的是不是就是該使用者,以及請求資訊是否被篡改。一般採用對請求資訊(請求uri,引數)進行摘要的方法來解決上述問題。由於摘要演算法的不可逆性,因此這種方式能夠在一定程度上防止資訊被篡改,保障通訊的安全。

1、MD5方式

使用者需要先在網站上申請key、secret,然後校驗流程如下:

客戶端

  1.引數排序

  2.將引數串接起來加上secret,生成待摘要字串

  3.使用MD5等摘要演算法生成摘要串signature

  4.將key,signature放入header中一併傳給伺服器
伺服器

  1.引數排序 

  2.將引數串接起來加上secret(通過header中的key在資料庫獲取),生成待摘要字串 

  3.使用MD5等摘要演算法生成摘要串 

  4.服務端生成的摘要串與客戶端通過header傳遞過來的摘要串進行比較

 

2、HmacSHA256方式

使用者需要先在網站上申請key、secret,然後校驗流程如下:

客戶單

  1.將請求引數封裝成json字串,也就是請求體body

  2.使用HmacSHA256演算法加secret對(請求url+nonce+body)加密生成摘要signature  

  3.將key,signature放入header中一併傳給伺服器


伺服器

  1.獲取請求中的請求體body字串

  2.使用HmacSHA256演算法加secret(通過header中的key在資料庫獲取)對(請求url+nonce+body)加密生成摘要signature 

  3.服務端生成的摘要串與客戶端通過header傳遞過來的摘要串進行比較

注意使用HmacSHA256更加安全,而且我們可以直接將請求引數封裝成json字串放入請求體中(也就是通過io流)進行傳遞。

 

實際使用中遇到的問題:

1、帶有下劃線的header被過濾

    當我們在使用HmacSHA256進行認證的時候,需要客戶端將請求key,signature放入header,name設定為api_key,api_signature,這時出現一個問題是伺服器怎麼都獲取不到這兩個值,但是我在本機測試時沒有問題的。後來才想起來是不是由於使用nginx做叢集而部分頭被過濾了,檢視過後果然是nginx將帶有下劃線的header name過濾了,後來修改nginx配置便可以正常獲取頭資訊。不過後來伺服器使用了第三方的動態加速再次把帶有下劃線的header name給過濾了,為了避免麻煩索性修改程式將header name中的下劃線都去掉了。

2、確保每次請求唯一性

    由於http都是明文請求,雖然我們可以通過摘要進行一定的安全保證確保資訊不被篡改,但是我們無法保證每次請求的唯一性,也就是如果請求資料被別人獲取再次請求,此時也可能帶來很嚴重的安全性問題。於是我們便需要使用者在每次請求中設定一個遞增的引數nonce,來確保每次請求都是唯一的。不過這樣也可能帶來一個問題,就是如果使用者近乎同時發起兩個請求a b,由於網路阻塞,可能後發起的b先到達伺服器,這樣當a達到的時候,伺服器會認為a的nonce已過期請求非法而拒絕。為了解決這樣的問題我們允許使用者設定一個expire值來避免nonce認證帶來的問題。

3、SNI

    由於當時我們有不同的工程(不同的域名,跟不同的證書)位於同一臺伺服器,這樣有的客戶端訪問我們api工程會拋異常,說http握手失敗或者說請求域名與伺服器證書不匹配而失敗。所以我們需要客戶端程式支援sni,它允許客戶端在發起SSL握手請求時(具體說來,是客戶端發出SSL請求中的ClientHello階段),就提交請求的Host資訊,使得伺服器能夠切換到正確的域並返回相應的證書。對於java語言來說jdk7的後續版本已經支援sni,或者使用httpclient 4.3及以後版本都可以很好的支援sni了。