I want to implement custom encryption middleware for API calls. At first, I read request body (IOwinContext.Request.Body
) and headers (Encryption-Key & Signature). Then, I decrypt request body, which gives me pure json string. Now comes the tricky part: I want to write this json back to IOwinContextRequest.Body
, so it can be deserialized to object and later passed as an argument for Controller method. Here's what I do:
Startup:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use(typeof(EncryptionMiddleware));
...
}
}
Middleware:
public class EncryptionMiddleware : OwinMiddleware
{
public EncryptionMiddleware(OwinMiddleware next) : base(next)
{
//
}
public async override Task Invoke(IOwinContext context)
{
var request = context.Request;
string json = GetDecryptedJson(context);
MemoryStream stream = new MemoryStream();
stream.Write(json, 0, json.Length);
request.Headers["Content-Lenght"] = json.Lenght.ToString();
request.Body = stream;
await Next.Invoke(context);
}
}
Now, what I get is this error:
System.Web.Extensions.dll!System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializePrimitiveObject() Exception thrown: 'System.ArgumentException' in System.Web.Extensions.dll
Additional information: Invalid JSON primitive: 8yi9OH2JE0H0cwZ.
Where original IOwinContext.Request.Body
is:
8yi9OH2JE0H0cwZ/fyY5Fks4nW(...omitted...)PvL32AVRjLA==
So I assumed that you cannot change request body this way. To test this, I've rewritten middleware like this:
public async override Task Invoke(IOwinContext context)
{
var request = context.Request;
string requestBody = new StreamReader(request.Body).ReadToEnd();
Debug.WriteLine(requestBody); // Prints "ORIGINAL BODY"
string newBody = "\"newBody\"";
MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(newBody));
request.Headers["Content-Length"] = newBody.Length.ToString();
request.Body = memStream;
await Next.Invoke(context);
}
Now I thought that Controller method should receive "ORIGINAL BODY" instead of "newBody", but I actually got this error:
System.dll!System.Diagnostics.PerformanceCounter.InitializeImpl() Exception thrown: 'System.InvalidOperationException' in System.dll
Additional information: The requested Performance Counter is not a custom counter, it has to be initialized as ReadOnly.
The question is: what is wrong with my approach? What is the correct way to rewrite request body? Is there any sufficient workaround? BTW: Decryption of data is tested and is flawless, so error should not originate there.
EDIT: before you answer/comment, TLS is already used. This is another layer of security. I am NOT reinventing the wheel. I'm adding a new one.