【轉】整套完整安全的API介面解決方案

來源:互聯網
上載者:User

標籤:密碼   帳號   ota   程式   div   .com   方式   cti   簽名   

原文地址:http://www.cnblogs.com/hubro/p/6248353.html

在各種手機APP泛濫的現在,背後都有同樣泛濫的API介面在支撐,其中魚龍混雜,直接裸奔的WEB API大量存在,安全性令人堪優

在以前WEB API概念沒有很普及的時候,都採用自已定義的介面和結構,對於公開訪問的介面,專業點的都會做下安全驗證,資料簽名之類

反而現在,誰都可以用WEB API估介面,安全性早忘一邊了,特別是外包小公司的APP項目,80%都有安全性漏洞(面試了大半年APP開發得出的結論)

特在過年之前,整理了下在用的解決方案,本方案解決了

  • 資料安全問題
  • 標準訊息結構
  • 介面測試程式
  • 介面文檔體現

本文

資料結構

對於一個介面,返回的內容除了要返回業務資料外,還得返回處理狀態,並且這個狀態是在每個介面都得有

所以資料格式都會定義為:

資料頭(描述資料資訊)

-----------------------------------

資料體(具體資料)

本文定義結構為

/// <summary>    /// 處理結果    /// </summary>    public class DealResult    {        /// <summary>        /// 處理結果        /// </summary>        public bool Result        {            get;            set;        }        /// <summary>        /// 訊息        /// </summary>        public string Message        {            get;            set;        }        /// <summary>        /// 關聯資料        /// </summary>        public object Data        {            get;            set;        }    }

  

所有介面都返回此對象,會描述本次請求的狀態,和對應的資料,服務端則根據實際情況,返回處理結果和對應的資料

 

資料安全

開方式介面安全性就不用多說了,解決方案為加密,或資料簽名驗證,本文方案為進行資料簽名

同返回的資料一樣,提交到伺服器的資料格式也統一約定,定義一個資料頭基類

/// <summary>    /// 參數基類    /// </summary>    [Serializable]    public class ParameBase    {        string time = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");        /// <summary>        /// 時間 格式 yyyy-MM-dd hh:mm:ss        /// </summary>        public string Time        {            get            {                return time;            }            set            {                time = value;            }        }        /// <summary>        /// 來源網站 = 1, IOS = 2,Android = 3,  = 4        /// </summary>        public int SourceFrom        {            get;            set;        }        /// <summary>        /// 簽名        /// </summary>        public string Token        {            get;            set;        }           }

  一個登入對象表示為

/// <summary>    /// 登入    /// </summary>    public class Login : ParameBase    {        /// <summary>        /// 使用者名稱        /// </summary>        public string Name        {            get;            set;        }        /// <summary>        /// 密碼        /// </summary>        public string Password        {            get;            set;        }    }

  

資料簽名表示為(KEY稍後講到)

Token=MD5(屬性值1+值2....+KEY)

按此對象表示為 MD5(Name+PassWord+Source+Time+KEY)

如果是GET參數怎麼辦,一樣,按參數名計算,同時傳遞的參數要附帶上Source,Time,Token 

 

密鑰機制

有的喜歡把密鑰放在用戶端,或固定密鑰,顯然都有安全問題,解決方案是動態擷取

這就意味著在設計介面時,有一個介面是首先要調用的,讓伺服器返回密鑰,於是就有了登入的概念

過程表示為

登入>返回使用者資訊和密鑰=>儲存使用者資訊和密鑰=>使用密鑰調用其它介面

這樣只有登入者和伺服器才知道自已的密鑰了

綜上所述,資料結構表示為

用戶端提交結構為 ParameBase(附帶簽名資訊)

服務端返回結構為 DealResult

 

登入機制

同網頁請求一樣,怎麼知道多次調用是同一個人呢,這裡採用了COOKIE的形式,登入後服務端返回一個COOKIE,用戶端再請求時帶上這個COOKIE

服務端需要儲存這個COOKIE標識,所有的驗證處理都會基於此標識來判斷使用者

 

有了上面基礎,進入項目階段

WEB API項目

其實用什麼項目類型都行,只是WEB API方便了對象結構序列化和傳參

預設WEB API路由RESUFUL形式,沒有控制器方法,只能按METHOD來定義,很不方便,改成控制器的形式,這樣就能用方法名來訪問了

更改路由配置為

12345 config.Routes.MapHttpRoute(                name: "DefaultApi",                routeTemplate: "api/{controller}/{action}/{id}",//加上路由ACTION參數                defaults: new { id = RouteParameter.Optional }            );

在此文,資料分為請求和返回,以登入返回使用者資訊為例,登入狀態請求,使用者資訊為返回,樣本對象結構為

使用者物件

/// <summary>    /// 登入返回使用者    /// </summary>    public class User    {        /// <summary>        /// 使用者編號        /// </summary>        public int Id        {            get;            set;        }        /// <summary>        /// 名稱        /// </summary>        public string Name        {            get;            set;        }        /// <summary>        /// 本次登入的KEY        /// </summary>        public string Key        {            get;            set;        }        /// <summary>        /// 本資登入的憑證        /// </summary>        public string Voucher        {            get;            set;        }           }

請求方式

這裡只採用了GET,POST兩種方式,根據實際情況定義,控制器方法一定需要都標明,不然會出現路由BUG

定義登入方法

/// <summary>        /// 登入        /// </summary>        /// <param name="parame"></param>        /// <returns>User</returns>        [HttpPost]        [AnonymousSign]        public DealResult Login([FromBody] Login parame)        {            if (parame.Password != "123")            {                return DealResult(false, "密碼不正確");            }            string key2 = System.Guid.NewGuid().ToString();            string voucher = System.Guid.NewGuid().ToString();            var user = new User() { Name = parame.Name, Id = 1, Key = key2, Voucher = voucher };            var timeDiff = (DateTime.Now - Convert.ToDateTime(parame.Time)).TotalSeconds;//儲存用戶端和服務端時間差            LoginStatusContext.SetLoginStatus(voucher, user.Id, key2, timeDiff);            CoreHelper.CookieHelper.AddCookies("user", voucher);//存入COOKIE            return DealResult(true, "", user);        }

這裡可以看到,建立了兩個GUID,一個為使用者憑證,一個為使用者密鑰,放入使用者資訊返回,同時調用LoginStatusContext.SetLoginStatus儲存登入資訊

同時使用了AnonymousSign標註,此方法使用預設簽名Setting.DefaultKey

定義擷取用資訊方法

/// <summary>        /// 基本資料        /// </summary>        /// <param name="name">參數name</param>        /// <returns>User</returns>        [HttpGet]        public DealResult GetBasicInfo(string name)        {            var user = new User() { Name = name, Id = CurrentUserId };            return DealResult(true, string.Empty, user);        }

樣本控制器完整定義

/// <summary>    /// 帳號操作    /// </summary>    [SignCheckAttribute]    public class AccountController : BaseController    {        /// <summary>        /// 登入        /// </summary>        /// <param name="parame"></param>        /// <returns>User</returns>        [HttpPost]        [AnonymousSign]        public DealResult Login([FromBody] Login parame)        {            if (parame.Password != "123")            {                return DealResult(false, "密碼不正確");            }            string key2 = System.Guid.NewGuid().ToString();            string voucher = System.Guid.NewGuid().ToString();            var user = new User() { Name = parame.Name, Id = 1, Key = key2, Voucher = voucher };            var timeDiff = (DateTime.Now - Convert.ToDateTime(parame.Time)).TotalSeconds;//儲存用戶端和服務端時間差            LoginStatusContext.SetLoginStatus(voucher, user.Id, key2, timeDiff);            CoreHelper.CookieHelper.AddCookies("user", voucher);//存入COOKIE            return DealResult(true, "", user);        }        /// <summary>        /// 基本資料        /// </summary>        /// <param name="name">參數name</param>        /// <returns>User</returns>        [HttpGet]        public DealResult GetBasicInfo(string name)        {            var user = new User() { Name = name, Id = CurrentUserId };            return DealResult(true, string.Empty, user);        }        /// <summary>        /// 測試異常        /// </summary>        /// <returns></returns>        [HttpGet]        public DealResult TestException()        {            int a = 0;            var b = 10 / a;            return DealResult(true);        }    }

此控制器標註了SignCheckAttribute用以進行簽名判斷

具體實現可看SignCheckAttribute代碼

SignCheckAttribute裡實現了有

  • 資料簽名判斷
  • 簽名逾時判斷
  • 使用者登入限制
  • 簽名重複使用處理(一個簽名只能使用一次)
  • 到期登入使用者處理(沒有主動退出使用者清理)

為了統一處理異常,配置了異常處理

1 GlobalConfiguration.Configuration.Filters.Add(new ExceptionAttribute());
對介面進行測試

大殺器來了,配合此方案放出了對應的測試載入器,雖然WEB API有個擴充,但沒法對此方案測試

使用此工具能方便按方案要求調用介面,為了方便參數拼接,POST和GET都採用URL參數的形式輸入

測試登入/api/account/login

測試擷取資訊/api/account/GetBasicInfo

測試異常處理/api/account/TestException

在未登入情況下調用擷取資訊

介面文檔

介面結構文檔一直是很讓人頭疼的事,手寫更改了又得維護,版本不一樣還麻煩,自動產生最好了,同樣WEB API 帶擴充沒法表示此結構詳細

大殺器2號來了,按代碼注釋動態產生介面文檔,文檔格式與控制器保持一致

Home控制器代碼實現

    public ActionResult Index(SummaryAnalysis.ExportType exportType = SummaryAnalysis.ExportType.NONE)        {            if (exportType != SummaryAnalysis.ExportType.NONE)            {                var str = SummaryAnalysis.Load(exportType);                return File(str, "application/octet-stream", "Model_" + exportType + ".zip");            }            else            {                if (string.IsNullOrEmpty(outPut))                {                    outPut = SummaryAnalysis.Load(exportType);                }                ViewBag.OutPut = outPut;                return View();            }        }    }

在見過的開發文檔,我覺得這是最好的展現形式了,還有錨點,快速定位到對象結構,並且與原始碼保持一致

附WEB API 內建文檔產生區別

附上項目源碼

http://pan.baidu.com/s/1c2rDacK

項目結構:

         ----------WPF測試程式

         ----------介面樣本

雖然跟CRL快速開發架構無關,但還是加上CRL的名,好文要頂!

【轉】整套完整安全的API介面解決方案

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.