0

I have a ASP.NET Core 3.1 API where I have not used CORS. As I understand, CORS is a browser thing. And as my ajax calls from another site on another origin is blocked to the API endpoints (which is great), I can still reach the same endpoints by using Postman or a HttpClient and GetAsync() calls.

My question is of it's possible to also block server-to-server calls (or Postman calls) to my API? Or like CORS, only allow certain origins?

Most of my endpoints are protected by a bearer JWT token, but I have an anonymous endpoint that I would like to let only origins I control (or can configure) to have access to that anonymous API.

Mats Magnem
  • 1,207
  • 1
  • 10
  • 15
  • Does this answer your question? [Is there any way to block HTTP requests made by Postman in .NET Core?](https://stackoverflow.com/questions/58231669/is-there-any-way-to-block-http-requests-made-by-postman-in-net-core) – Bryan Lewis Nov 25 '20 at 23:01
  • No, sorry. This has nothing to do with CORS. But I found a way to get what I need by creating my own Authorize attribute by using "TypeFilterAttribute" and "IAuthorizationFilter". May not work for everyone in all scenarios, but it helped me filter out origins (by using the "Referer" header) and returning Unauthorized when there was no match. Seem to work for all kinds of request (ajax, Postman, HttpContext.GetAsync etc) – Mats Magnem Nov 26 '20 at 13:58

1 Answers1

0

I solved it after i bumped in to this post on stackoverflow:

How do you create a custom AuthorizeAttribute in ASP.NET Core?

I simply made a custom Authorize attribute [ApiAuthorize()], that I call this way:

[ApiController]
[ApiAuthorize(new string[] { "https://localhost:44351", "https://mysite.onthe.net" })]
public class MyInternalApiController : ControllerBase
{
   ...
}

It may also be implemented on the Action instead of the Controller. The implementation was done like this:

public class ApiAuthorizeAttribute : TypeFilterAttribute
{
    public ApiAuthorizeAttribute(string[] origins) : base(typeof(ApiAuthorizeFilter))
    {
        Arguments = new object[] { origins };
    }
}

public class ApiAuthorizeFilter : IAuthorizationFilter
{
    readonly string[] _origins;

    public ApiAuthorizeFilter(string[] origins)
    {
        _origins = origins;
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        if (_origins == null)
            return;

        string referer = context.HttpContext.Request.Headers["Referer"].ToString();
        if (string.IsNullOrWhiteSpace(referer) || !_origins.Any(origin => referer.StartsWith(origin, StringComparison.OrdinalIgnoreCase)))
            context.Result = new ForbidResult();
    }
}

Things to consider:

  • The implementation and check of the referer could be exact match instead of StartsWith
  • The handling could use RegEx or any good alternative to handle subdomains, wildcards etc
  • The referer could be translated to a Uri objects to get better results and variations
  • A jQuery ajax call gets a "403 - Forbidden" as expected, but Postman gets a "404 - Not Found". To me that does not matter, but that's something to look into if it matters.

But it covers what I need, so I'm happy with this.

Mats Magnem
  • 1,207
  • 1
  • 10
  • 15