چگونه API های عمومی را در ASP.NET Core ایمن کنیم؟

ASP.NET Core یک ساختار محبوب است. مزایای کلیدی آن شامل ویژگی هایی مانند اجرای کراس پلتفرم، عملکرد بالا، تزریق وابستگی داخلی و خط لوله درخواست HTTP مدولار است.
چالش ها
هسته ASP.NET از بسیاری از ارائه دهندگان احراز هویت پشتیبانی می کند تا برنامه ها را از طریق گردش کار احراز هویت متعدد ایمن کنند. با این حال، در بسیاری از سناریوها، ما مجبوریم یک برنامه/سایت وب ارائه کنیم که بر اساس یک API احراز هویت نشده با دسترسی ناشناس است.
به عنوان مثال، ما لیستی از محصولات را در پایگاه داده داریم و می خواهیم این محصولات را در یک صفحه وب نمایش دهیم. ما میتوانیم یک API برای ارائه فهرستی از محصولات بنویسیم و بخش جلویی (وبسایت) میتواند این فهرست را از طریق API دریافت کرده و در صفحه وب محصولات عمومی ما نمایش دهد.
بدون اعمال سطح امنیتی، چنین معماریهایی میتوانند آسیبپذیری امنیتی باز در برابر بهرهبرداری باشند.
کنترل های امنیتی موجود در ASP.NET
ASP.NET راه حل هایی برای آسیب پذیری های رایج از جمله هسته ارائه می دهد
- اسکریپت بین سایتی
- تزریق SQL،
- جعل درخواست بین سایتی (CSRF)
- تغییر مسیرها را باز کنید
یک قدم جلوتر رفتن
به عنوان توسعه دهندگان، ما همچنین باید از برنامه های خود در برابر سایر بردارهای حمله رایج محافظت کنیم
- انکار سرویس توزیع شده (DDOS)
- انکار سرویس (DOS)
- خروجی داده های انبوه
- پاسخ کاوشگر
- خراش دادن
دو مرحله ای که می توانیم برای تأیید سرصفحه ارجاع دهنده و محدود کردن نرخ انجام دهیم که در زیر به تفصیل مورد بحث قرار گرفته است.
از فیلتر اقدام محدودیت درخواست مبتنی بر IP استفاده کنید
ما میتوانیم مشتریان را به تعداد معینی از درخواستها در یک دوره زمانی مشخص محدود کنیم تا از حملات مخرب ربات جلوگیری کنیم. ما فیلتر اعمال محدودیت درخواستی مبتنی بر IP را در هسته ASP.NET ایجاد کردهایم. به خاطر داشته باشید که چندین مشتری میتوانند پشت یک آدرس IP واحد بنشینند، بنابراین شما میتوانید این را در محدوده خود برآورده کنید، یا آدرس IP را با سایر دادههای درخواست ترکیب کنید تا درخواستها منحصربهفردتر شوند.
برای امتحان فیلتر، فقط باید یک ActionAttribute را در بالای اکشن کنترلر اضافه کنید.
بیشتر بخوانید: Asp.net Core Api با Entity Framework
[HttpGet()]
[ValidateReferrer]
[RequestLimit("Test-Action", NoOfRequest = 3, Seconds = 10)]
publicasync Task<actionresult>GetAsync(CancellationTokenct)
{
// code here
}</actionresult>
در اینجا پیاده سازی فیلتر است:
namespace Security.Api.Filters
{
using System;
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Memory;
[AttributeUsage(AttributeTargets.Method)]
public class RequestAttribute :ActionFilterAttribute
{
public RequestAttribute(string name)
{
Name = name;
}
public string Name
{
get;
}
public intNoOfRequest
{
get;
set;
} = 1;
public int Seconds
{
get;
set;
} = 1;
private static MemoryCachememoryCache
{
get;
} = new MemoryCache(new MemoryCacheOptions());
public override void OnActionExecuting(ActionExecutingContext context)
{
varipAddress = context.HttpContext.Request.HttpContext.Connection.RemoteIpAddress;
varmemoryCacheKey = $ "{Name}-{ipAddress}";
memoryCache.TryGetValue(memoryCacheKey, out intprevReqCount);
if (prevReqCount>= NoOfRequest)
{
context.Result = new ContentResult
{
Content = $ "Request is exceeded. Try again in seconds.",
};
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.TooManyRequests;
}
else
{
varcacheEntryOptions = new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds(Seconds));
memoryCache.Set(memoryCacheKey, (prevReqCount + 1), cacheEntryOptions);
}
}
}
}
فیلتر اقدام بررسی ارجاع را اضافه کنید
برای محافظت از API در برابر سوء استفاده و ایجاد محافظت اضافی در برابر حملات جعل درخواست متقابل (CSRF)، بررسی های امنیتی روی سرصفحه ارجاع درخواست برای هر درخواست REST API ارسال شده به سرور انجام می شود.
این API تأیید می کند که درخواست از کجا آمده است. ما یک Referrer Check Action Filter در ASP.NET Core ایجاد کرده ایم. از دسترسی به ابزارهایی مانند POSTMEN، سرویس گیرنده REST و غیره جلوگیری می کند.
شما فقط باید یک ActionAttribute را به بالای Action کنترلر اضافه کنید.
[HttpGet()]
[ValidateReferrer]
publicasync Task<actionresult>GetAsync(CancellationTokenct)
{
// your code here
}</actionresult>
در اینجا اجرای فیلتر است
namespace Security.Api.Filters
{
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using System;
using System.Linq;
using System.Net;
[AttributeUsage(AttributeTargets.Method)]
public sealed class ValidateAttribute :ActionFilterAttribute
{
private IConfiguration _configuration;
public ValidateAttribute() { }
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 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 false;
//Allows to check customer list
varUrls = _configuration.GetSection("CorsOrigin").Get<string[]>()?.Select(url => new Uri(url).Authority).ToList();
//add current host for swagger calls
var host = request.Host.Value;
Urls.Add(host);
bool isValidClient = Urlsl.Contains(new Uri(referrerURL).Authority);
// comapre with base uri
return isValidClient;
}
}
}
</string[]>
آیا به دنبال توسعه دهنده وب اختصاصی ASP.Net Core هستید؟ جستجوی شما در اینجا به پایان می رسد.
میان افزار DoSattack را اضافه کنید
اگر مقیاس خودکار را پیکربندی کرده باشید، حملات DOS API های شما را تحت تأثیر قرار می دهد و آنها را غیرمجاز و/یا گران می کند. راه های مختلفی برای جلوگیری از این مشکل از طریق throttling درخواست وجود دارد. در اینجا گزینه ای برای استفاده از واسطه ها برای محدود کردن تعداد درخواست ها از آدرس های IP مشتری ذرات وجود دارد.
در زیر کد DosAttackMiddleware.cs آمده است
namespace Security.Api.Middlewares
{
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Timers;
public sealed class DosAttackMiddleware
{
private static IDictionary _IpAdresses = new Dictionary();
private static Stack _Banded = new Stack();
private static Timer _Timer = CreateTimer();
private static Timer _BannedTimer = CreateBanningTimer();
private
const int BANNED_REQUESTS = 10;
private
const int REDUCTION_INTERVAL = 1000;
private
const int RELEASE_INTERVAL = 3 * 60 * 1000; // 3 minutes
private RequestDelegate _next;
public DosAttackMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContexthttpContext)
{
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 CreateTimer()
{
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 TimerElapsed(object sender, ElapsedEventArgs e)
{
foreach (string key in _IpAdresses.Keys.ToList())
{
_IpAdresses[key]--;
if (_IpAdresses[key] == 0) _IpAdresses.Remove(key);
}
}
}
}
نتیجه
یک API غیرمجاز قابل سوء استفاده است. ما باید با افزودن کد اضافی از بردار حمله صریح جلوگیری کنیم. امیدواریم این وبلاگ اجرای این محدودیتها را آسانتر کند و در عین حال زندگی این مهاجمان را دشوارتر کند.