1. 程式人生 > >使用過濾器對mvc api接口安全加密

使用過濾器對mvc api接口安全加密

display 控制 aspnet 示例 .com res 過度設計 sys req

asp.net api接口安全

安全要求:

b1.防偽裝攻擊(案例:在公共網絡環境中,第三方 有意或惡意 的調用我們的接口)

b2.防篡改攻擊(案例:在公共網絡環境中,請求頭/查詢字符串/內容 在傳輸過程被修改)

b3.防重放攻擊(案例:在公共網絡環境中,請求被截獲,稍後被重放或多次重放)

b4.防數據信息泄漏(案例:截獲用戶登錄請求,截獲到賬號、密碼等)

設計原則

1.輕量級

2.適合於異構系統(跨操作系統、多語言簡易實現)

3.易於開發

4.易於測試

5.易於部署

6.滿足接口安全需求(滿足b1 b2 b3要求),無過度設計。

其它:接口安全要求b4部分,主要針對目前用戶中心的登錄接口

設計原則是:使用HTTPS安全協議 或 傳輸內容使用非對稱加密,目前我們采用的後者

適用範圍

1.所有寫操作接口(增、刪、改 操作)

2.非公開的讀接口(如:涉密/敏感/隱私 等信息)

api 接口安全驗證 過濾器代碼

技術分享圖片
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using test.Models;
using TEST.Common; namespace test.Filters { /* * 第一步:登錄系統,獲取appkey * 第二步:http請求頭headers加入字段appid,sign,timestamp三個字段,appid:用戶名,sign:簽名值(後面詳細解說),timestamp:當前時間戳 ,如:2017/12/12 17:11:9 值為: 1513069869 * 第三步:把業務請求的參數傳入到http消息體Body(x-www-form-urlencoded) * 第四步:計算sign值,對除簽名外的所有請求參數按 參數名+值 做的升序排列,value值無需編碼 * 整個流程示例如下: * appkey=D9U7YY5D7FF2748AED89E90HJ88881E6 (此參數不需要排序,而是加在文本開頭和結尾處) * headers參數如下 * appid=user1 * sign=??? * timestamp=1513069265 * body參數如下 * par1=52.8 * par2=這是一個測試參數 * par3=852 * * 1)按 參數名+值 以升序排序,結果:appiduser1par152.8par2這是一個測試參數par3852timestamp1513069265 * 2)在本文開頭和結尾加上登錄時獲取的appkey 結果為:D9U7YY5D7FF2748AED89E90HJ88881E6appiduser1par152.8par2這是一個測試參數par3852timestamp1513069265D9U7YY5D7FF2748AED89E90HJ88881E6 * 3)對此文本進行md5 32位 大寫 加密,此時就是sign值 結果為:B44C81F3DF4D5E8A614C84977D33E8D2
*/ /// <summary> /// api接口加密身份驗證過濾器 /// </summary> public class VerificationFilters : IAuthorizationFilter { /// <summary> /// 接口簽名驗證 /// </summary> /// <param name="context"></param> public void OnAuthorization(AuthorizationFilterContext context) { ModelResult modelResult = new ModelResult(); //參數判斷 if (!context.HttpContext.Request.Headers.ContainsKey("appid")) { modelResult.code = -1; modelResult.message = "缺少appid參數!"; JsonResult json = new JsonResult(modelResult); context.Result = json; } else if (!context.HttpContext.Request.Headers.ContainsKey("sign")) { modelResult.code = -1; modelResult.message = "缺少sign參數!"; JsonResult json = new JsonResult(modelResult); context.Result = json; } else if (!context.HttpContext.Request.Headers.ContainsKey("timestamp")) { modelResult.code = -1; modelResult.message = "缺少timestamp參數!"; JsonResult json = new JsonResult(modelResult); context.Result = json; } else { string appid = context.HttpContext.Request.Headers["appid"]; string sign = context.HttpContext.Request.Headers["sign"]; string timestamp = context.HttpContext.Request.Headers["timestamp"]; DateTime requestTime = DateTimeHelper.GetTime(timestamp); // 接口過期 int apiExpiry = 20; if (requestTime.AddSeconds(apiExpiry) < DateTime.Now) { modelResult.code = -3; modelResult.message = "接口過期!"; JsonResult json = new JsonResult(modelResult); context.Result = json; } else { //從數據庫或緩存查找對應的appkey, string appkey = "fdsafdsafdsafasdfasdf"; if (!string.IsNullOrEmpty(appkey)) { modelResult.code = -4; modelResult.message = "appid不存在!"; JsonResult json = new JsonResult(modelResult); context.Result = json; return; } //是否合法判斷 SortedDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>(); sortedDictionary.Add("appid", appid); sortedDictionary.Add("timestamp", timestamp); //獲取post數據,並排序 Stream stream = context.HttpContext.Request.Body; byte[] buffer = new byte[context.HttpContext.Request.ContentLength.Value]; stream.Read(buffer, 0, buffer.Length); string content = Encoding.UTF8.GetString(buffer); context.HttpContext.Request.Body = new MemoryStream(buffer); if (!String.IsNullOrEmpty(content)) { string postdata = System.Web.HttpUtility.UrlDecode(content); string[] posts = postdata.Split(new char[] { & }); foreach (var item in posts) { string[] post = item.Split(new char[] { = }); sortedDictionary.Add(post[0], post[1]); } } //拼接參數,並在開頭和結尾加上key StringBuilder sb = new StringBuilder(appkey); foreach (var item in sortedDictionary) { sb.Append(item.Key).Append(item.Value); } sb.Append(appkey); if (sign != CryptographyHelper.Md5_Encryption(sb.ToString())) { modelResult.code = -2; modelResult.message = "簽名不合法!"; JsonResult json = new JsonResult(modelResult); context.Result = json; } } } } } }
View Code

使用方式

技術分享圖片
using Microsoft.AspNetCore.Mvc;
using test.Filters;

namespace TEST.Controllers
{
    [TypeFilter(typeof(VerificationFilters))]
    public class HomeController : Controller
    {
        //此接口就使用接口驗證過濾器,從控制器上繼承下來的        
        public IActionResult Index()
        {
            return Json("aa");
        }

        //此接口就使用接口驗證過濾器,在action頭標記了過濾器,可單獨作用於action
        [TypeFilter(typeof(VerificationFilters))]
        public IActionResult Index2()
        {
            return Json("aa");
        }        
    }
}
View Code

調用檢證接口示例

技術分享圖片
/// <summary>
        /// 
        /// </summary>
        /// <param name="appid">身份碼</param>
        /// <param name="appkey">驗證碼</param>
        /// <param name="timestamp">時間</param>
        /// <param name="role">角色</param>
        /// <param name="identity">設備碼</param>
        /// <param name="version">版本</param>
        /// <param name="data">數據</param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult api(string appid, string appkey, int timestamp, int role, int identity, string version, string data)
        {
            if (timestamp == 0)
            {
                timestamp = DateTimeHelper.ConvertDateTimeInt(DateTime.Now);
            }
            SortedDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>();
            sortedDictionary.Add("appid", appid);
            sortedDictionary.Add("timestamp", timestamp.ToString());
            sortedDictionary.Add("role", role.ToString());
            sortedDictionary.Add("identity", identity.ToString());
            sortedDictionary.Add("version", version);
            string val = "";
            try
            {
                string[] dataitem = data.Split("\r\n");
                foreach (var item in dataitem)
                {
                    string[] tmp = item.Split(=);
                    sortedDictionary.Add(tmp[0], tmp[1]);
                }
            }
            catch (Exception)
            {
                val = "data數據格式有問題!";
                ViewBag.Data = val;
                return View();
            }
            StringBuilder sb = new StringBuilder(appkey);
            foreach (var p in sortedDictionary)
                sb.Append(p.Key).Append(p.Value);
            sb.Append(appkey);
            string sign = CryptographyHelper.Md5_Encryption(sb.ToString());
            val = $" appid:{appid}\r\n sign:{sign}\r\n timestamp:{timestamp}\r\n {data}";
            ViewBag.Data = val;
            return View();
        }
View Code

源碼下載地址 https://files.cnblogs.com/files/fengmazi/test.rar

技術在於分享,大家共同進步

使用過濾器對mvc api接口安全加密