Asp.Net Core Web API’s Security Best Practices

Asp.Net Core Web API’s Security Best Practices

In the modern digital landscape, Web APIs are critical for enabling communication between different systems and services. However, they also present a lucrative target for attackers. Ensuring the security of your Web APIs is paramount. In this blog post, we’ll explore best practices for securing Web APIs in .NET C#.

  1. Data Protection using HTTPS only.
  2. Authentication.
  3. Token Expiry and Rotation.
  4. Role-Based Access Control (RBAC).
  5. Input Validation.
  6. Rate Limiting and Throttling.
  7. CORS (Cross-Origin Resource Sharing)
  8. Logging and Monitoring.

We will cover every section in detail and will see it in action. So let’s get started.

1- Data Protection using HTTPS only:

Always use HTTPS to encrypt data in transit. Avoid using HTTP to prevent data from being intercepted. HTTPS is more securable and reliable protocol.

Program.cs

app.UseHttpsRedirection();        

Copy

2- Authentication:

Always use a strong authentication mechanism to protect our API more securely, allowing only authenticated users. We can achieve robust authentication mechanisms such as OAuth, OpenID Connect, or JWT (JSON Web Tokens). Avoid basic authentication with plaintext passwords.

Perform the following steps.

  • Create a new Asp.Net Web API Project.
  • Add a new controller named AuthController.
  • Install the nuget package “Microsoft.AspNetCore.Authentication.JwtBearer” d) Now, add the following code.

AuthController.cs:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace BlogApiApp.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AuthController : ControllerBase
    {
    private readonly IConfiguration _configuration;
    List<UserLoginModel> UserList;
    public AuthController(IConfiguration configuration)
    {
        _configuration = configuration;
        UserList = new List<UserLoginModel>();
        UserList.Add(new UserLoginModel { Username = "admin", Password = "admin123" });
        UserList.Add(new UserLoginModel { Username = "Jhon", Password = "Jhon123"});
    }
    [HttpPost("login")]
    public IActionResult Login([FromBody] UserLoginModel user) {
        //Validate user credentials(this is just an example, replace with your logic)
        var UserListRes = UserList.Where(x => x.Username ==
        user.Username && user.Password == user.Password).FirstOrDefault();
        if (UserListRes != null)
        {
        //2- JWT Token Auth.
        var token = GenerateJwtToken(UserListRes.Username,
        "Admin");
        return Ok(new { Token = token });
        }
        return Unauthorized();
        }
    private string GenerateJwtToken(string username, string role) {
    try
    {
    var jwtSettings =
    _configuration.GetSection("JwtSettings");
    var securityKey = new
    SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["Key"])); var credentials = new SigningCredentials(securityKey,
    SecurityAlgorithms.HmacSha256);
    var claims = new List<Claim>
    {
    new Claim(ClaimTypes.Name, username),
    new Claim(ClaimTypes.Role, role) // Assign Role
    dynamically
    };
    var token = new JwtSecurityToken(
    issuer: jwtSettings["Issuer"],
    audience: jwtSettings["Audience"],
    claims: claims,
    expires:
    DateTime.Now.AddMinutes(Convert.ToDouble(jwtSettings["ExpiryInMinutes"])), signingCredentials: credentials
    );
    return new JwtSecurityTokenHandler().WriteToken(token);
    }
    catch (Exception ex)
    {
    throw ex;
    }
    }
    }
    }
    public class UserLoginModel
    {
    [Required]
    public string Username { get; set; }
    [Required]
    public string Password { get; set; }
}        

Copy

Pragram.cs:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using System.Reflection.Metadata;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
#region Configure JWT authentication
var jwtSettings = builder.Configuration.GetSection("JwtSettings"); builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme =
JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme =
JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters {
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings["Issuer"],
ValidAudience = jwtSettings["Audience"],
IssuerSigningKey = new
SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["Key"])) };
});
#endregion
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();        

Copy

Appsetting.json:

{
"AllowedHosts": "*",
"JwtSettings": {
"Issuer": "YourIssuer",
"Audience": "YourAudience",
"Key": "YourVeryStrongSecretKeyThatIsLongEnough123456"
}
}        

Copy

Test Result:

Now, Let’s run the Web API project by pressing F5 and hitting the API through Postman. Finally, our API worked and returned the token.

3- Token Expiry and Rotation:

Ensure that tokens have a short lifespan and can be rotated regularly. Use refresh tokens for obtaining new access tokens. As you can see we have setup the token expiry is 15 mins.

Appsetting.json:

{
"AllowedHosts": "*",
"JwtSettings": {
"Issuer": "YourIssuer",
"Audience": "YourAudience",
"Key": "YourVeryStrongSecretKeyThatIsLongEnough123456",
"ExpiryInMinutes": 15 //Token Timeout.
}
}        

Copy

Test Results: Token expired after 15 minutes. Now you have to generate a new token and then would be able to access again against that token.

4- Role-Based Access Control (RBAC)

Implement role-based access control to restrict access to API endpoints based on user roles. 4 (i). Every user must have role assigned.

  1. a) Create a new controller “StudentController.cs”.
  2. b) Add the [Authorize] on the top of the HTTP method which can only be accessible to authorized users only.
  3. c) Create new HTTP methods for Admin and User roles.

d) Admin will be able to access the GetSecureData & WelcomeAdmin methods. e) User will be able to access the GetSecureData & WelcomeUser methods......

.

.

.

.

.

READ MORE HERE: https://burq.io/blog/asp-net-core-web-apis-security-best-practices/

要查看或添加评论,请登录