1

I have a very simple webservice with one GET method that has a token string parameter. I use this token can have letters, "+" and "/". Ex.: mC1SW7RJhgsQGtRHhsg/Q+FGoZjbBleNKtpqT7zLMtE

I use this token to look in the database if there is data for this token.

My method in the controller is like that:

[HttpGet("{token}")]
[ProducesResponseType(typeof(string), 200)]
[ProducesResponseType(typeof(void), 404)]
public JsonResult Get(string token)
{
    string sql = "SELECT dataObject FROM Session WHERE id = @SessionToken";
    var data = _conn.QueryFirstOrDefault<Session>(sql, new {SessionToken = token});
    if (data == null){
        var r = Json(string.Empty);
        r.StatusCode = StatusCodes.Status404NotFound;
        return r;
    }
    else {
        return Json(JsonConvert.DeserializeObject(data.dataObject));
    }
}

I see Dapper/Webapi automatically escapes this parameter and change "/" to "%2F" for example.

When I deploy it just works for tokens without special characters and return 404.

As a workaround I changed the token in the server to encode the token and replace the encoded plus sign to space:

string decodedToken = WebUtility.UrlDecode(token);
token = decodedToken.Replace(" ", "+");

The problem is that I need my clients to do the inverse and replace the '+' sign:

var encodedToken = WebUtility.UrlEncode(token);
// Convert '+' to ' '
token = encodedToken.Replace("%2B", " ");

What is the recommended way to work without asking the client to replace de '+' signs?

staticdev
  • 2,950
  • 8
  • 42
  • 66
  • If you control the token that they receive, you can Encode it when you deliver the token to them in the first place? https://stackoverflow.com/questions/26353710/how-to-achieve-base64-url-safe-encoding-in-c – Dylan Sep 24 '19 at 20:11

2 Answers2

1

For some reason Kestrel or .NET MVC do a partial decode in a encoded URL. This looks like a BUG (https://github.com/aspnet/Mvc/issues/6388), but there is a workaround.

With the token you passed in question you would encode it in the client:

 Original Token: mC1SW7RJhgsQGtRHhsg/Q+FGoZjbBleNKtpqT7zLMtE   
 Encoded Token: mC1SW7RJhgsQGtRHhsg%2FQ%2BFGoZjbBleNKtpqT7zLMtE

See that '/' became '%2F' and '+' became '%2B'. This is because these two characters are part of the composition of a URL. Therefore to pass them fully to WebApi they must be replaced with their ASCII representation.

You would call your service with the encoded token like this:

 http://myserver:1234/myservice/token/mC1SW7RJhgsQGtRHhsg%2FQ%2BFGoZjbBleNKtpqT7zLMtE

In your service, because of the bug, you would receive from Kestrel/MVC the following string partially decoded:

 Partially decoded token: mC1SW7RJhgsQGtRHhsg%2FQ+FGoZjbBleNKtpqT7zLMtE

Just implement a simple replace:

 token.Replace("%2F", "/");

And your string will be full decoded.

Daniel Reis
  • 850
  • 9
  • 10
0

Try to add below code in your web.config:

<system.webServer>
   <security>
      <requestFiltering allowDoubleEscaping="true" />
   </security>
</system.webServer>

Refer to Dotnet core + (plus) sign in Web API routing

Ryan
  • 19,118
  • 10
  • 37
  • 53