How to display server side validation error message? - c#
We are building up a web application and we are having some issue in displaying server side validation error messages in frontend.
To give some context, we are running a single page application where frontend is implemented in react.js and backend api in asp.net. There are a number of forms in our application we ask users to fill in, and we plan to implement form validation both on client side and server side.
The work flow we are having now is to do client side validation first, and then pass the data to backend api. Backend then would first do the same validation frontend just did, to make sure that the request does not come from a malicious user who has bypassed clientside validations rules. For a request that comes from the normal channel, it should never fail this step and if it does, however, it simply means we are dealing with a hacker.
However, there are a bit more than that in server side validation. There are information which client side has no knowledge of, e.g. is the Bank Account user just typed exists in our database ? (we don't have a dedicated api to verify this, so we have to do this at the form level after user submitted the entire form to server side).
So in conclusion, there are two parts of server side validation rules: basic validation rules that is shared with frontend, and advanced validation rules that requires database access which is only available at server side.
Now the question is, how do we inform user after they fail these two type of validations?
Below are two proposals we have come about so far
Solution 1: use HTTP 400 - Bad Request to denote a business failure
we treat that 2 types of server side validation the same way and when any request fails any validation, we send back a HTTP 400 with a json object containing detailed error messages saying why it fails. A sample response would be
HTTP 400 Bad Request
{
"bsb_name" :"bsb_name has special characters",
"bsb_number":"bsb number doesn't exist",
"amount":"amount is required"
}
Now the problem is, we are not the only party who can return HTTP 400. As we are using asp.net framework plus OWIN framework, the frameworks themselves can also send back HTTP 400 under a certain circumstances , and the HTTP 400 they send is quite different from us. This create extra work for frontend to differentiate 2 types of HTTP 400 and deal with them in different ways.
A proposal was made to to re-factor our response and instead of sending back JSON object, we send back plain string --- based on the assumption that asp.net framework/owin would send back their HTTP 400 in plain string (1). So at front end we don't have differentiate them and can handle both of them in the same way. Besides, to avoid introducing magic delimiters, we only return the first error message text rather than all of them. So a sample response could be
HTTP 400 Bad Request
"Bank account name has special characters"
and we are going to treat it the same way as a HTTP 400 returned by the asp.net framework, say,
HTTP 400 Bad Request
Request header too long
So in both cases, a site user would see an error message after submitting their form saying "Bank account name has special characters" or "Request header too long"
solution 2 : Use Business Protocol rather HTTP Protocol
If the request fails the basic server side validation, which can only happen for hackers, server would throw exception immediately which would end up with a HTTP 500. Once receiving the HTTP 500, client side would simply direct user to a general error page saying something unexpected happened without any detailed information -- we try to avoid being hacking friendly.
If the request fails the advanced server side validation though, which can happen to a normal application user, server will still return a HTTP 200 - Success, but with a different status_code denoting that this is a error response. e.g.
HTTP 200 Success
{
status_code: Err_123
error_message: "bsb doesn't exist"
}
I personally want to go with solution 2 but was told that we shouldn't use HTTP 200 for a validation error. As HTTP 200 stands for OK, using HTTP 200 in the case of server side validation failure doesn't make sense.
My understanding is, HTTP Status code is designed for HTTP protocol, and should have nothing to do with your business logic. A HTTP 200 only means client has sent the request to the server, and server has successfully handled it returned the response. Whether the response means transaction has been approved, or transaction has been rejected, or, the BSB_Number you submitted doesn't exists, it simply doesn't care. And it should NOT care.
So in the case where a transaction does get rejected, or the form has some invalid input that can only be detected at server side, we still should respond HTTP 200 but assign a different status_code, which is the equivalent of HTTP 400, BUT, it's in our business protocol. So effectively, we should distinct our business protocol from http protocol, and we can't use HTTP FAILURE to stand for a BUSINESS FAILURE(2).
Above is all my thought on this, and I welcome all comments, further discussion on this topic.
Cheers,
Bo
(1): the assumption is wrong as I recently found out that IIS can return HTTP 400 under some circumstance. When that happens, it return a HTML page.
(2): An analogy could be
**IP -- TCP -- HTTP -- BUSINESS**
If TCP layer fails, IP shouldn't be concerned;
If HTTP layer fails, TCP shouldn't be concerned;
If BUSINESS layer fails, HTTP shouldn't be concerned;
Isn't 'separate of concern' a common sense in programming?? I'm a bit surprised when seeing that somebody says "it's ok to return HTTP 400 in case of business failure"
Separation of concerns ought to be first and foremost in my opinion.
Solution one, although stating the error originates in the business layer, implies that presentation is at fault. Now it's ambiguous as to where the error is actually originating.
On the other hand, solution 2 verbosely states that the HTTP transaction was successful and that the business logic responded with an error.
Ideally (in my opinion) all errors in the server side should be trapped and reported as an error in the business logic, so that the only time HTTP errors are thrown is when the user requests a bad or sensitive page.
This causes the system to fail more gracefully, and makes it more scaleable. (If you implement your API elsewhere for example, you don't need to include the HTTP error handling in it, only the display of said error)
As an aside, this might be better suited for P.SE and not SO.
My solution is similar to solution 2. I define an entity as the response for all RESTful request.
class Entity<T>{
public int code {get;set;}
public int message {get;set;}
public T content {get;set;}
}
Whether the request is succeeded or failed, the front would get an entity and check the code. If code is 200 (or others defined), continue processing the content, otherwise display the message and return.
For a request that comes from the normal channel, it should never fail this step and if it does, however, it simply means we are dealing with a hacker.
if your API its public, why not use status code 500,...This is a way to trick people trying to access your API. But, you now if this not internal server error with read status message. Or you use Status Code 202 (The request has been accepted for processing, but the processing has not been completed. The request may or may not eventually be acted upon, as it may be disallowed when processing actually takes place. there is no facility for status returns from asynchronous operations such as this.)
if you use status code 200 or 400, and every body to know if that can be injected...but, up to you, this just my suggestion like what you need opinion.
In my opinion your 400 response code is ok. You actually need to model how you should respond to validation scenarios. For example a BaseResponse.cs would look something like this.
public class BaseResponse<T> where T: object {
public T Data {get;set;}
public bool Success {get; set;}
public IList<Error> Errors {get;set;}
}
On the other hand you may define the error class as follows
public class Error {
string Type {get;set;} // "validation", "business"
string Code {get;set;} // "VAL_1234", "BIZ_4321"
string Message {get;set;} // "Value should be greater than 10"
}
Now on the Javascript side in the react application your code is not that complicated
fetch(url)
.then((response)=> {
if(response.status === 400) {
let json = response.json();
if(json) { // you have validation errors, do something with errors property in json
}else { // 400 was returned because of some other reason
}
}
});
A more involved solution in conjunction with what I have above should work. Sample here
Related
What response should i return in case of error from an external API?
I'm working on changes for an old user creation endpoint in a dotnet API. In a specific endpoind for the creation of users, besides many things i'm calling Zerobounce API to validate the email of the user. In the application that get's the response from this API it needs to act differently if the issue comes from Zerobounce, which is an email validation API. What i've already done is: When it fails i'll return a response with a status code 409. Which i'm not sure is the best choice but seemed fine at the beginning, but is now a problem since it can be returned in another case that doesn't involve Zerobounce . The complete response when an error is returned is of the type: Different solutions i thinked about: Different ReasonPhrase for each different error with the same status code. Which means for Zerobounce errors i can tell there whats happening. Using custom Response Headers, with this i can create for example 2 headers, one that creates a sub status code and another with the reason of failure or something else. this seems more versatile. Start sending a body in case it fails, this might involve lots more changes, because the way the api, and website that calls the endpoint only expects a body when we have a success response, god knows where else it might break if i use this approach. Any suggestion as the best approach is appreciatted.
Returning meaningful HTTP responses in ASP.NET Core 2.0 Web API [closed]
Closed. This question is opinion-based. It is not currently accepting answers. Want to improve this question? Update the question so it can be answered with facts and citations by editing this post. Closed 5 years ago. Improve this question I feel it's a good idea to return meaningful HTTP responses but I'm trying to come up with the right approach to handle that. In my ASP.NET Core Web API app, the endpoints i.e. API action methods, simply receive a request, call my business layer for a response and return the response. At the business layer, I check to see if the request is authorized or not. If it's not authorized, I throw an exception that incdicates the type of exception i.e. unauthorized request but in those cases, my API endpoint simply returns an HTTP 500. I'd rather return an HTTP 401. Question is how to transfer my lower level exceptions to HTTP status codes. Two questions: Is it worth trying to capture the type of exception that occurred at a lower level in the app and try to translate it to HTTP responses or should I simply let my API return an HTTP 500? If it's worth it, how do I handle it?
Assuming that your controller extends Microsoft.AspNet.MVC.Controller you'll have inherited some methods that do what you need like OK, Forbidden, BadRequest, ObjectResult, etc.. So in the case you've described above you could do something like public async IActionResult DoMyThing() { try { return ObjectResult(await DoMyInternalCall()); } catch (Exception e) { //FigureOut the Exception type indications a security violation return Forbidden() } .... Personally I prefer to build APIs that return a status instead of throwing an exception which makes this all a bit cleaner especially now that we have tuples. So something like public async IActionResult DoMyThing() { var (Status status, string myThing) = await DoMyInternalCall(); switch(status) { case Status.OK: return ObjectResult(myThing); break; case Status.AccessDenied: return Forbidden(); break; case Status.NotFound: return Notfound(); ... That's just a taste thing though - I don't judge. The point is, Microsoft.AspNet.MVC.Controller has built in methods to let you return valid HTTP status codes along with data.
I don't like this idea of throwing exceptions at all. A 500 is a sign that there is something really wrong with your own code. So, let's say that your business layer is checking to see if a user is authorised. What I would do is create a method which checks the authorisation, have that method return a simple Boolean response for example. Then your controller checks the flag, if it's false, return 401, job done. This is a much better way of communicating between your business layer and api layer. Obviously I have no way of knowing how your business layer is built, but keep it simple, keep it clear, don't try to trap any exceptions, deal with everything cleanly and return appropriate HTTP codes. The business layer should not care at all about the api, should not deal with HTTP codes, basically this means you are not leaking abstractions everywhere and you keep things in the layer where they belong.
A Web API should strive to never return a 500 status code (Internal Server Error). If it does, then there is something wrong with the code you have written. Having said that, you shouldn't be throwing an exception with the intent to send back a status code is a rather poor way to handle requests -- i.e. by doing a blanket catch all and masking it with some nice status code to the client. You should run all your validation and logic on the request and send back your choice of any of the 4xx status codes. Essentially, for a Web API the status codes should be 2XX -- Success //(ex: OK, created, no content, etc) 3XX -- Redirection //(ex: renamed an API's path/url to a new one) 4XX -- Client Error ex: 405 //Method Not Allowed (ex: client sent a DELETE request to your API) 409 //Conflict 415 //Unsupported Media Type (ex: client requests for XML -- yuck! no!) 416 //Range Not Suitable (ex: client asked for a million records) 422 //Unpronounceable Entity (ex: client sent something invalid in the body) 5XX -- Server Error //(ex: a well written Web API will NEVER error! ) However, if you really do have an exception, then a 500 error code is correct -- that means you wrote bad code (refer back to my first point).
There's a whole host of HTTP response codes of course, and just because a request couldn't be properly handled doesn't necessarily mean it's a 500 Internal Server error. What if someone requests an update to a non-existent object? That wouldn't fall under the range of a 500 (unsure offhand exactly which would work - 4xx I'd guess, but a handy list of common HTTP responses while you're working on this would be recommended). I generally feel that 500s are for "uh oh, something happened on our end and we don't know what..." type of thing. For most other cases there's a more appropriate response. With that said, I feel that exceptions are best generalized as they move further toward the top layers. Entity Framework throws some esoteric exception, the data access layer wraps it up in a slightly more generic DataAccessException (with the original as the inner, of course), the repository maybe handles it even more generically, and by the time it gets to your controller for response handling, you should only have a handful of "actual" exceptions that ought to need to be handled. Return something fairly generic, log the nested exceptions on the server, and go from there? My 2cents
How do I find out if a server is active or not based on HttpStatus code?
I have a test application that validates URLs to check if a particular service is up. Trouble is, I am validating a range of URLs which will send me a variety of Http Statuses, for eg: 200(OK) is valid and 302(Found) is also valid. But 500 or 404 is not valid. I'm not sure which Http Statuses indicate the service is up and running? Do we have a whitelist or any other reliable method to validate this?
Even getting 200 does not mean that the server is doing what you want it to do really, since you can have a handler that masks all exception or what not. So it totally depends on what you want to verify. If you just want to check the server is responding, then all the statuses will do, since even 500 with the db exception means your server is running and responding to your requests. Generally 4xx and 5xx are client and server error and you can use that. Just check wiki page. But if you want something more reasonable, you'll need to parse the responses to verify it contains something that you expect.
Validate SharePoint REQUESTDIGEST for a GET request?
I have a WCF REST service hosted in SharePoint that uses SSOM. The client web application sends AJAX requests containing the REQUESTDIGEST in a X-RequestDigest header. I am using the typical SPWeb.ValidateFormDigest() for my POST requests to prevent CSRF vulnerabilities. Works great. Here's the weird part. Our client uses HP Fortify, and it is reporting that our GET requests are vulnerable to CSRF attacks. My GET requests are indempotent so this seems silly, but I must be compliant. To get around it, I want to use ValidateFormDigest() in my WCF method for the GET request the same way I do for POST, but it throws this exception: "Updates are currently disallowed on GET requests. To allow updates on a GET, set the 'AllowUnsafeUpdates' property on SPWeb." I tried setting AllowUnsafeUpdates, but that just makes the request succeed without validating the digest! Is there a way to have SPWeb validate the digest within a GET request?
HP Fortify gives recommendations, not edicts. If you think - and can prove - that the warning is spurious, then justifying the pattern should be treated as being compliant. Code analysis tools are not perfect.
Server side redirect truncating request payloads
I'm on IIS 6 and I have an ASP.Net 4.0 site that's a single page to serve as a SOAP reverse proxy. I have to modify the return content in order to delete a trouble node from the response and add a tracking node. In order to facilitate its function as a reverse proxy for all addresses, I have the 404 on the server set to a custom "URL" of "/default.aspx" (the page for my app) For requests without a payload, it works perfectly - such as for ?WSDL Urls. It requests the proper URL from the target system, gets the response and sends it back - it's pretty utterly transparent in this regard. However, when a SOAP request is being made with an input payload, the Request.InputStream in the code is always empty. Empty - with one exception - using SOAPUI, I can override the end point and send the request directly to /default.aspx and it will receive the input payload. Thus, I have determined that the custom 404 handler is - when server-side transferring the request - stripping the payload. I know the payload is being sent - I have even wiresharked it on the server to be sure. But then when I add code to log the contents of Request.InputStream it's blank - even though Request.ContentLength shows the right content length for the original request. I've also been looking for a good way to use ASP.Net to intercept the requests directly rather than allowing the normal IIS 404 handler to take care of it but even with a wildcard mapping, I can't seem to get the settings right nor am I fully confident that it would help. (But I'm hoping it would?) Finally, I don't have corporate permission to install MVC framework. Thus, I need either some configuration for IIS I am missing to make this work properly or some other method of ensuring that I get the request payload to my web page. Thanks!
What about using an HTTP Handler mapped to all requests? You'll need to add a wildcard application mapping as detailed here and correctly configure your HTTP Handler.