前言
在app開放接口api的設計中,避免不了的就是安全性問題,因為大多數接口涉及到用戶的個人信息以及一些敏感的數據,所以對這些 接口需要進行身份的認證,那么這就需要用戶提供一些信息,比如用戶名密碼等,但是為了安全起見讓用戶暴露的明文密碼次數越少越好,我們一般在web項目 中,大多數采用保存的session中,然后在存一份到cookie中,來保持用戶的回話有效性。但是在app提供的開放接口中,后端服務器在用戶登錄后 如何去驗證和維護用戶的登陸有效性呢,以下是參考項目中設計的解決方案,其原理和大多數開放接口安全驗證一樣,如淘寶的開放接口token驗證,微信開發 平台token驗證都是同理。
簽名設計
對於敏感的api接口,需使用https協議
https是在http超文本傳輸協議加入SSL層,它在網絡間通信是加密的,所以需要加密證書。
https協議需要ca證書,一般需要交費。
簽名的設計
原理:用戶登錄后向服務器提供用戶認證信息(如賬戶和密碼),服務器認證完后給客戶端返回一個Token令牌,用戶再次獲取信息時,帶上此令牌,如果令牌正取,則返回數據。對於獲取Token信息后,訪問用戶相關接口,客戶端請求的url需要帶上如下參數:
時間戳:timestamp
Token令牌:token
然后將所有用戶請求的參數按照字母排序(包括timestamp,token),然后更具MD5加密(可以加點鹽),全部大寫,生成sign簽名,這就是 所說的url簽名算法。然后登陸后每次調用用戶信息時,帶上sign,timestamp,token參數。
例如:原請求https://www.andy.cn/api/user/update/info.shtml?city=北京 (post和get都一樣,對所有參數排序加密)
加上時間戳和token
https://www.andy.cn/api/user/update/info.shtml?city=北京×tamp=12445323134&token=wefkfjdskfjewfjkjfdfnc
然后更具url參數生成sign
最終的請求如
https://www.andy.cn /api/user/update/info.shtml?city=北京×tamp=12445323134& token=wefkfjdskfjewfjkjfdfnc&sign=FDK2434JKJFD334FDF2
其最終的原理是減小明文的暴露次數;保證數據安全的訪問。
具體實現如下:
1. api請求客戶端想服務器端一次發送用用戶認證信息(用戶名和密碼),服務器端請求到改請求后,驗證用戶信息是否正確。
如果正確:則返回一個唯一不重復的字符串(一般為UUID),然后在Redis(任意緩存服務器)中維護Token----Uid的用戶信息關系,以便其他api對token的校驗。
如果錯誤:則返回錯誤碼。
2.服務器設計一個url請求攔截規則
(1)判斷是否包含timestamp,token,sign參數,如果不含有返回錯誤碼。
(2)判斷服務器接到請求的時間和參數中的時間戳是否相差很長一段時間(時間自定義如半個小時),如果超過則說明該 url已經過期(如果url被盜,他改變了時間戳,但是會導致sign簽名不相等)。
(3)判斷token是否有效,根據請求過來的token,查詢redis緩存中的uid,如果獲取不到這說明該token已過期。
(4)根據用戶請求的url參數,服務器端按照同樣的規則生成sign簽名,對比簽名看是否相等,相等則放行。(自然url簽名 也無法100%保證其安全,也可以通過公鑰AES對數據和url加密,但這樣如果無法確保公鑰丟失,所以簽名只是很大程 度上保證安全)。
(5)此url攔截只需對獲取身份認證的url放行(如登陸url),剩余所有的url都需攔截。
3.Token和Uid關系維護
對於用戶登錄我們需要創建token--uid的關系,用戶退出時需要需刪除token--uid的關系。
簽名實現
獲取全部請求參數
String sign = request.getParameter("sign"); Enumeration<?> pNames = request.getParameterNames(); Map<String, Object> params = new HashMap<String, Object>(); while (pNames.hasMoreElements()) { String pName = (String) pNames.nextElement(); if("sign".equals(pName))continue; Object pValue = request.getParameter(pName); params.put(pName, pValue); }
生成簽名
public static String createSign(Map<String, String> params, boolean encode) throws UnsupportedEncodingException { Set<String> keysSet = params.keySet(); Object[] keys = keysSet.toArray(); Arrays.sort(keys); StringBuffer temp = new StringBuffer(); boolean first = true; for (Object key : keys) { if (first) { first = false; } else { temp.append("&"); } temp.append(key).append("="); Object value = params.get(key); String valueString = ""; if (null != value) { valueString = String.valueOf(value); } if (encode) { temp.append(URLEncoder.encode(valueString, "UTF-8")); } else { temp.append(valueString); } } return MD5Utils.getMD5(temp.toString()).toUpperCase(); }
轉載 http://www.lai18.com/content/944366.html
http://www.cnblogs.com/whcghost/p/5657594.html
傳統身份驗證方法
Cookie驗證是一種比較傳統的HTTP安全策略。Cookie驗證機制就是為一次請求認證在服務端創建一個Session對象,同時在客戶端的瀏覽器端創建了一個Cookie對象;通過客戶端帶上來Cookie對象來與服務器端的Session對象匹配來實現狀態管理的。
默認的,當我們關閉瀏覽器的時候,cookie會被刪除。但可以通過修改cookie 的過期時間使Cookie在一定時間內有效。
基於 Token 的身份驗證方法
使用基於Token的身份驗證方法,在服務端不需要存儲用戶的登錄記錄。基本流程如下:
(1)客戶端使用用戶名密碼請求登錄;
(2)服務端收到請求,驗證用戶名與密碼。驗證成功服務端簽發一個Token,再把這個Token發送給客戶端;
(3)客戶端每次向服務端發起請求,都需要帶着服務端最新簽發的Token;
(4)服務端收到請求,驗證請求里面的Token,如果驗證成功返回請求的數據。流程圖如下:
Token身份驗證的優勢
(1)支持跨域訪問:Cookie是不允許垮域訪問的,這一點對Token機制是不存在的,前提是傳輸的用戶認證信息通過HTTP頭傳輸;
(2)更適用CDN:可以通過內容分發網絡請求你服務端的所有資料,而你的服務端只要提供API即可;
(3)去耦:不需要綁定到一個特定的身份驗證方案。Token可以在任何地方生成,只要在你的API被調用的時候,你可以進行Token生成調用即可;
(4)更適用於移動應用:如果客戶端是一個原生平台(比如 iOS,Android,Windows 8 等),是不支持Cookie的,需要額外通過Cookie容器進行處理,這時采用Token驗證機制就會簡單得多。