<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Dotnet Core Public API的安全實(shí)踐

          共 6105字,需瀏覽 13分鐘

           ·

          2020-08-19 11:52

          公開API的安全,其實(shí)更重要。

          ?

          一、API的安全

          作為一個(gè)Dotnet Core的老司機(jī),寫API時(shí),能兼顧到API的安全,這是一種優(yōu)雅。

          ?

          通常,我們會(huì)用認(rèn)證來保證API的安全,無敵的Authorize能解決我們很多的問題。

          但是,總有一些場(chǎng)合,我們沒辦法用Authorize,而只能用匿名或不加驗(yàn)證的方式來訪問。比方電商中查詢SKU的列表并在前端展示,通常這個(gè)無關(guān)用戶和權(quán)限,在完成API的時(shí)候,我們也不會(huì)加入認(rèn)證Authorize

          這種情況下,如果直接寫,不加入安全級(jí)別,這樣的體系結(jié)構(gòu)是有可能成為可供利用的安全漏洞的。

          ?

          Dotnet Core框架已經(jīng)提供了一些常見漏洞的解決方法,包括:

          • 跨站點(diǎn)腳本

          • SQL注入

          • 跨站點(diǎn)請(qǐng)求偽造(CSRF)

          • 重定向

          等等。

          但是,我們還需要更進(jìn)一步,還需要照顧到以下常見的攻擊:

          • 拒絕服務(wù)(DOS)

          • 分布式拒絕服務(wù)(DDOS)

          • 批量API調(diào)用

          • 探測(cè)響應(yīng)

          • 數(shù)據(jù)抓取

          這部分內(nèi)容,需要我們自己實(shí)現(xiàn)。當(dāng)然,這部分內(nèi)容的實(shí)現(xiàn),也可以從Web Server上進(jìn)行設(shè)置。

          本文討論的,是代碼的實(shí)現(xiàn)。

          二、相關(guān)代碼

          今天偷個(gè)懶,不講原理,以分享代碼為主。

          2.1 基于IP的客戶端請(qǐng)求限制

          通過限制客戶端在指定的時(shí)間范圍內(nèi)的請(qǐng)求數(shù)量,防止惡意bot攻擊。

          代碼中,我建立了一個(gè)基于IP的請(qǐng)求限制過濾器。

          注意:有多個(gè)客戶端位于同一個(gè)IP地址的情況,這個(gè)情況在這個(gè)代碼中沒有考慮。如果您希望實(shí)現(xiàn)這一點(diǎn),可以把幾種方式結(jié)合起來使用。

          以下是代碼:

          [AttributeUsage(AttributeTargets.Method)]
          public?class?RequestLimitAttribute?:?ActionFilterAttribute
          {
          ????public?string?Name?{?get;?}
          ????public?int?NoOfRequest?{?get;?set;?}
          ????public?int?Seconds?{?get;?set;?}

          ????private?static?MemoryCache?Cache?{?get;?}?=?new?MemoryCache(new?MemoryCacheOptions());

          ????public?RequestLimitAttribute(string?name,?int?noOfRequest?=?5,?int?seconds?=?10)
          ????
          {
          ????????Name?=?name;
          ????????NoOfRequest?=?noOfRequest;
          ????????Seconds?=?seconds;
          ????}
          ????public?override?void?OnActionExecuting(ActionExecutingContext?context)
          ????
          {
          ????????var?ipAddress?=?context.HttpContext.Request.HttpContext.Connection.RemoteIpAddress;
          ????????var?memoryCacheKey?=?$"{Name}-{ipAddress}";

          ????????Cache.TryGetValue(memoryCacheKey,?out?int?prevReqCount);
          ????????if?(prevReqCount?>=?NoOfRequest)
          ????????{
          ????????????context.Result?=?new?ContentResult
          ????????????{
          ????????????????Content?=?$"Request?limit?is?exceeded.?Try?again?in?{Seconds}?seconds.",
          ????????????};
          ????????????context.HttpContext.Response.StatusCode?=?(int)HttpStatusCode.TooManyRequests;
          ????????}
          ????????else
          ????????{
          ????????????var?cacheEntryOptions?=?new?MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds(Seconds));
          ????????????Cache.Set(memoryCacheKey,?(prevReqCount?+?1),?cacheEntryOptions);
          ????????}
          ????}
          }

          使用時(shí),只要在需要的API前加屬性即可:

          [HttpGet]
          [RequestLimit("DataGet",?5,?30)]
          public?IEnumerable?Get()
          {
          ????...
          }

          2.2 引用頭檢查

          對(duì)API請(qǐng)求的請(qǐng)求引用頭進(jìn)行檢查,可以防止API濫用,以及跨站點(diǎn)請(qǐng)求偽造(CSRF)攻擊。

          同樣,也是采用自定義屬性的方式。

          public?class?ValidateReferrerAttribute?:?ActionFilterAttribute
          {
          ????private?IConfiguration?_configuration;

          ????public?override?void?OnActionExecuting(ActionExecutingContext?context)
          ????
          {
          ????????_configuration?=?(IConfiguration)context.HttpContext.RequestServices.GetService(typeof(IConfiguration));

          ????????base.OnActionExecuting(context);

          ????????if?(!IsValidRequest(context.HttpContext.Request))
          ????????{
          ????????????context.Result?=?new?ContentResult
          ????????????{
          ????????????????Content?=?$"Invalid?referer?header",
          ????????????};
          ????????????context.HttpContext.Response.StatusCode?=?(int)HttpStatusCode.ExpectationFailed;
          ????????}
          ????}
          ????private?bool?IsValidRequest(HttpRequest?request)
          ????
          {
          ????????string?referrerURL?=?"";

          ????????if?(request.Headers.ContainsKey("Referer"))
          ????????{
          ????????????referrerURL?=?request.Headers["Referer"];
          ????????}
          ????????if?(string.IsNullOrWhiteSpace(referrerURL))?return?true;

          ????????var?allowedUrls?=?_configuration.GetSection("CorsOrigin").Get<string[]>()?.Select(url?=>?new?Uri(url).Authority).ToList();

          ????????bool?isValidClient?=?allowedUrls.Contains(new?Uri(referrerURL).Authority);

          ????????return?isValidClient;
          ????}
          }

          這里我用了一個(gè)配置,在appsetting.json中:

          {
          ??"CorsOrigin":?["https://test.com",?"http://test1.cn:8080"]
          }

          CorsOrigin參數(shù)中加入允許引用的來源域名:端口列表。

          使用時(shí),在需要的API前加屬性:

          [HttpGet]
          [ValidateReferrer]
          public?IEnumerable?Get()
          {
          ????...
          }

          2.3 DDOS攻擊檢查

          DDOS攻擊在網(wǎng)上很常見,這種攻擊簡(jiǎn)單有效,可以讓一個(gè)網(wǎng)站瞬間開始并長(zhǎng)時(shí)間無法響應(yīng)。通常來說,網(wǎng)站可以通過多種節(jié)流方法來避免這種情況。

          下面我們換一種方式,用中間件MiddleWare來限制特定客戶端IP的請(qǐng)求數(shù)量。

          public?class?DosAttackMiddleware
          {

          ????private?static?Dictionary<string,?short>?_IpAdresses?=?new?Dictionary<string,?short>();
          ????private?static?Stack<string>?_Banned?=?new?Stack<string>();
          ????private?static?Timer?_Timer?=?CreateTimer();
          ????private?static?Timer?_BannedTimer?=?CreateBanningTimer();

          ????private?const?int?BANNED_REQUESTS?=?10;
          ????private?const?int?REDUCTION_INTERVAL?=?1000;?//?1?second????
          ????private?const?int?RELEASE_INTERVAL?=?5?*?60?*?1000;?//?5?minutes????
          ????private?RequestDelegate?_next;

          ????public?DosAttackMiddleware(RequestDelegate?next)
          ????
          {
          ????????_next?=?next;
          ????}
          ????public?async?Task?InvokeAsync(HttpContext?httpContext)
          ????
          {
          ????????string?ip?=?httpContext.Connection.RemoteIpAddress.ToString();

          ????????if?(_Banned.Contains(ip))
          ????????{
          ????????????httpContext.Response.StatusCode?=?(int)HttpStatusCode.Forbidden;
          ????????}

          ????????CheckIpAddress(ip);

          ????????await?_next(httpContext);
          ????}

          ????private?static?void?CheckIpAddress(string?ip)
          ????
          {
          ????????if?(!_IpAdresses.ContainsKey(ip))
          ????????{
          ????????????_IpAdresses[ip]?=?1;
          ????????}
          ????????else?if?(_IpAdresses[ip]?==?BANNED_REQUESTS)
          ????????{
          ????????????_Banned.Push(ip);
          ????????????_IpAdresses.Remove(ip);
          ????????}
          ????????else
          ????????{
          ????????????_IpAdresses[ip]++;
          ????????}
          ????}


          ????private?static?Timer?CreateTimer()
          ????
          {
          ????????Timer?timer?=?GetTimer(REDUCTION_INTERVAL);
          ????????timer.Elapsed?+=?new?ElapsedEventHandler(TimerElapsed);
          ????????return?timer;
          ????}

          ????private?static?Timer?CreateBanningTimer()
          ????
          {
          ????????Timer?timer?=?GetTimer(RELEASE_INTERVAL);
          ????????timer.Elapsed?+=?delegate?{
          ????????????if?(_Banned.Any())?_Banned.Pop();
          ????????};
          ????????return?timer;
          ????}

          ????private?static?Timer?GetTimer(int?interval)
          ????
          {
          ????????Timer?timer?=?new?Timer();
          ????????timer.Interval?=?interval;
          ????????timer.Start();
          ????????return?timer;
          ????}

          ????private?static?void?TimerElapsed(object?sender,?ElapsedEventArgs?e)
          ????
          {
          ????????foreach?(string?key?in?_IpAdresses.Keys.ToList())
          ????????{
          ????????????_IpAdresses[key]--;
          ????????????if?(_IpAdresses[key]?==?0)?_IpAdresses.Remove(key);
          ????????}
          ????}
          }

          代碼中設(shè)置:1秒(1000ms)中有超過10次訪問時(shí),對(duì)應(yīng)的IP會(huì)被禁用5分鐘。

          使用時(shí),在Startup.cs中直接加載中間件:

          public?void?Configure(IApplicationBuilder?app,?IWebHostEnvironment?env)
          {
          ????...
          ????app.UseMiddleware();
          ????...
          }

          三、結(jié)尾的話

          以上代碼僅為拋磚引玉之用。

          公開的API,未經(jīng)驗(yàn)證的API,在生產(chǎn)環(huán)境會(huì)因?yàn)榉N種原因被攻擊。這幾天公司的系統(tǒng)就因?yàn)檫@個(gè)出了大事。

          所以,寫API的時(shí)候,要充分考慮到這些網(wǎng)絡(luò)攻擊的可能性,通過正確的處理,來防止來自網(wǎng)絡(luò)的攻擊。

          這是一份責(zé)任,也是一個(gè)理念。

          與大家共勉!

          ?

          (全文完)

          ?

          本文的代碼,我已經(jīng)傳到Github上,位置在:https://github.com/humornif/Demo-Code/tree/master/0021/demo

          喜歡就來個(gè)三連,讓更多人因你而受益

          瀏覽 31
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天堂资源网在线观看 | 欧美精品性视频 | 大香蕉一级片 | 婷婷爱爱蜜臀天天操 | 老太色HD色老太HD. |