Security

Robert O'Donnell

Posted on
Sep 30 2013

Hey Bug Reports and Issues forum,

We're looking at using Raygun in one of our products, but we have a question about security of the API key.

Given that the API key is embedded in the JavaScript, what is there to prevent someone taking your API key and spamming error messages into Raygun? Looking at the application configuration page, it doesn't look like you provide the source URL for the web application.

Will this be addressed in a future version, or am I missing something?

Cheers,

Robert


John-Daniel Trask

Raygun

Posted on
Sep 30 2013

Hi Robert,

Thanks for your question. It's something that has come up a few times.

You're right, this could happen, but I'm not sure how we could look at making a client side script not use the API key (all our competitors do the same thing so I'm not sure if anyone has come up with how to make it secure). If you have some ideas on how you'd handle it, we're open to feedback.

Even if the client side scripts were sending the data back to your backend, there would be noting stopping a malicious user from simply seeing what the client side script was sending and just manually doing that themselves.

One thing we are planning is to allow you to reset an API key, so if you did become compromised you could simply make a new one.

Furthermore, when we do eventually add a public read API, we will be providing a different set of a keys for that activity.

I appreciate your concerns and do appreciate any feedback you might have on securing this further.

Kind regards,

John-Daniel Trask
Co-founder
Mindscape Limited


Robert O'Donnell

Posted on
Sep 30 2013

Hi John-Daniel,

Thanks for the quick response. This is pretty much what I expected to hear.

I can think of a couple of ways of increasing the security, you've probably already thought of these, but you may find some value here.

One way could be to restrict access to the Raygun service by source IP address and referrer URL. This is not entirely satisfactory as both referrer and IP address spoofing (albeit more difficult) is possible.

Another way would be to proxy the Raygun service via my own application server, so that only the application code has the API key.

Anyhow this is probably not going to be a road block for me, it's just good to know where things are at.

Cheers,

Robert


John-Daniel Trask

Raygun

Posted on
Sep 30 2013

Hi Robert,

Ultimately we'd need to do both of those things to tie it down. We can't lock the IP address because the errors are sent from the clients machine so the IP address is constantly changing. Proxing it back via your own server would work, but then ultimately they could just send the data back to your own server in a similar manner. It would have the downside of being more complicated to setup and only really acting as security through obscurity.

Glad it won't be a road block, but it is always good to keep looking at these things and seeing if we can think of something better :-)

Keep any other questions or feedback you have coming!

John-Daniel Trask
Co-founder
Mindscape Limited


Robert O'Donnell

Posted on
Sep 30 2013

Doh, and I just realised why the first method wont work. :)


Brian MacKay

Posted on
Feb 10 2022

Why not use a secure token on the server to generate a second, less secure token that has a limited lifespan or more limited permissions (if necessary)?

That's a common pattern in identity providers.


Chris Bush

Posted on
Feb 29 2024

Hi from the future. What I've done in scenarios like this when setting up a SPA app or something else that's going to run client side (in my case a Blazor WASM app) is create an authenticated endpoint on the server side that accepts a request and essentially proxies it to Raygun. So for example in my scenario, something like:

//ErrorHandlerController.cs (Server-side)
[ApiController]
[Route("[controller]")]
public sealed class ErrorHandlerController : Controller
{
    private readonly IRaygunClient _raygun;

    public ErrorHandlerController(IRaygunClient raygun)
    {
        _raygun = raygun;
    }


    [HttpPost("raygun")]
    public IActionResult LogRaygunErrorAsync(RaygunRequest request, CancellationToken ct = default)
    {
        _raygun.Send(request.Exception, request.Tags, request.Metadata);
        return Ok();
    }

}

//RaygunRequest.cs (Common library on server and client)
public sealed record RaygunRequest
{
    public required Exception Exception { get; set; }
    public IList<string> Tags { get; set; } = [];
    public Dictionary<string, object?> Metadata { get; set; } = [];
}


//RaygunClient.cs (client-side)
public interface IRaygunClient
{
    Task SendAsync(Exception ex, IList<string> tags, Dictionary<string, object?> metadata = null);
}

public sealed class RaygunClient : IRaygunClient
{
    private readonly IHttpClientFactory _httpClientFactory;

    public RaygunClient(IHttpClientFactory httpClientFactory)
    {
       _httpClientFactory = httpClientFactory;
    }

    public async Task SendAsync(Exception ex, IList<string> tags, Dictionary<string, object?> metadata = default)
    {
        var request = new RaygunRequest
        {
            Exception = ex,
            Tags = tags,
            Metadata = metadata
        };

        var client = _httpClientFactory.CreateClient("ServerSide");
        using var response = await client.PostAsync("/errorhandler/raygun", new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"));
        response.EnsureSuccessStatusCode();
    }
}

Then pretty much anywhere you need to log a client-side error to Raygun, just inject an IRaygunClient and use like you normally would. The ASP.NET Core app is authenticated against Azure AD so any requests coming into that endpoint have to have a valid login session or it'll get a 401 Unauthorized response, and so that way you're a) assuring that any requests coming in are properly authenticated as real users and b) never leaking your Raygun API key to the client's computer.


Reply