I have controller
public class BilingController : Controller
{
…
[HttpPost]
public string Result (string data)
{
…
}
…
}
Method Result can be caused only by foreign service process.anypayservice.com
How can I check url, is request from service process.anypayservice.com or other service?
Or allow only this url - process.payservice.com for method Result call
Any attribute or I should write custom?
You can check the HTTP_REFERER header, but note that it can be easily spoofed.
A better approach is to use some sort of token that can be passed in to your service for authentication.
Related
I am not sure if ServiceStack has a mechanism to prevent "JavaScript/HTML Injection" on Entities (Request Entities) properties.
Also as per my understanding entity's properties of type string is prone to JavaScript/HTML injection
If there is no in built mechanism please suggest me a better option.
One of the option which i see is use to validate may be using Fluent Validation or any other validating library
Use validation:
Yes you should be using Fluent Validation or another validation mechanism to sanitise all the values that are passed as a request to your ServiceStack service.
Why ServiceStack shouldn't sanitise for you:
ServiceStack won't do this for you, after all sending HTML and/or JavaScript in a request to the service may be perfectly legitimate, (i.e. where your service is a content manager for a blog), and it's wrong to assume the request is an injection attack.
ServiceStack isn't constricted to only being consumed by web applications, so it's up to the service to decide which values are appropriate.
It should be noted that ServiceStack does prevent SQL injection by escaping all parameters.
Encode HTML entities:
If you are concerned about HTML injection, then you should consider encoding HTML entities, then any unsafe values that are returned won't affect your result. You can do this easily using this request filter, and marking up your DTO with an attribute [EncodeHtml].
GlobalRequestFilters.Add((req,res,dto) => {
var dtoType = dto.GetType();
var filteredProperties = dtoType.GetPublicProperties().Where(p => p.PropertyType == typeof(string) && p.HasAttribute<EncodeHtmlAttribute>() && p.CanWrite);
foreach(var property in filteredProperties)
property.SetValue(dto, HttpUtility.HtmlEncode(property.GetValue(dto, null)), null);
});
On your DTO add the [EncodeHtml] attribute to the properties you want to protect.
[Route("/test", "GET")]
public class Test
{
public string UnsafeMessage { get; set; }
[EncodeHtml]
public string SafeMessage { get; set; }
}
The attribute declaration is simply:
public class EncodeHtmlAttribute : Attribute {}
Then when you send a request such as:
/test?unsafeMessage=<b>I am evil</b>&safeMessage=<b>I am good</b>
The result will be
UnsafeMessage: "<b>I am evil</b>"
SafeMessage: "<b>I am good</b>"
I hope this helps.
As per your suggestion if you want to throw an exception on any DTOs that may contain HTML then you could use a more general check which prevents any HTML in any strings on the DTO by checking against a regular expression, but I'd do this sparingly.
GlobalRequestFilters.Add((req,res,dto) => {
var dtoType = dto.GetType();
if(!dtoType.HasAttribute<PreventHtmlAttribute>())
return;
var filteredProperties = dtoType.GetPublicProperties().Where(p => p.PropertyType == typeof(string));
foreach(var property in filteredProperties){
var value = property.GetValue(dto, null) as string;
if(value != null && Regex.Match(value, #"<[^>]*>", RegexOptions.IgnoreCase).Success)
throw new HttpError(System.Net.HttpStatusCode.BadRequest, "400", "HTML is not permitted in the request");
}
});
Then use this attribute:
public class PreventHtmlAttribute : Attribute {}
On the DTO:
[PreventHtml]
[Route("/test", "GET")]
public class Test
{
...
}
I have two Odata action methods defined. The one with parameter gets invoked while the other without parameter doesnt get invoked and throws error No routing convention was found to select an action for the OData path with template '~/entityset'.
Here is the code of my action methods
[EnableQuery]
public IQueryable<User> GetUser()
{
return db.Users;
}
// GET: odata/User(5)
[EnableQuery]
public SingleResult<User> GetUser([FromODataUri] int key)
{
return SingleResult.Create(db.Users.Where(user => user.Id == key));
}
The query that I am using are as follows
http://bureauservice/api/odata/UserOdata - Doesnt work
http://bureauservice/api/odata/UserOdata(1) - works
Could someone tell me why the first link doesnt work.
Please change the name of the method which returns entityset to "Get[EntitySetName]" or "Get".
Change from
public IQueryable<User> GetUser()
To
public IQueryable<User> GetUserOdata()
Or
public IQueryable<User> Get()
Set the name of the first action as GetUsers (plural) because you are getting the whole collection of users while in the second you are asking for a single user.
You may want to add the parenthesis to the first URL:
http://bureauservice/api/odata/UserOdata()
If you are just starting to proactise odata, then Odata v4 is good start point, as it is an OASIS standard, but v3 is not.
Here is the v4 version Function sample:
https://github.com/OData/ODataSamples/tree/master/WebApiCore/ODataFunctionSample.
...guess I'm the first to ask about this one?
Say you have the following routes, each declared on a different controller:
[HttpGet, Route("sign-up/register", Order = 1)]
[HttpGet, Route("sign-up/{ticket}", Order = 2)]
... you could do this in MVC 5.0 with the same code except for the Order parameter. But after upgrading to MVC 5.1, you get the exception message in the question title:
Multiple controller types were found that match the URL. This can
happen if attribute routes on multiple controllers match the requested
URL.
So the new RouteAttribute.Order property is only controller-level? I know in AttributeRouting.NET you can do SitePrecedence too. Is the only way to have routes like the above when all actions are in the same controller?
Update
Sorry, I should have mentioned these routes are on MVC controllers, not WebAPI. I am not sure how this affects ApiControllers.
If you know that ticket will be an int you can specify that type in the route to help resolve the route:
[HttpGet, Route("sign-up/register")]
[HttpGet, Route("sign-up/{ticket:int}")]
This approach worked for me, per user1145404's comment that includes a link to Multiple Controller Types with same Route prefix ASP.NET Web Api
In case of Attribute routing, Web API tries to find all the controllers which match a request. If it sees that multiple controllers are able to handle this, then it throws an exception as it considers this to be possibly an user error. This route probing is different from regular routing where the first match wins.
As a workaround, if you have these two actions within the same controller, then Web API honors the route precedence and you should see your scenario working.
There are two ways to fix this:
A regex constraint, like here: MVC Route Attribute error on two different routes
Or a custom route constraint, like here: https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/
You can create custom route constraints by implementing the IRouteConstraint interface. For example, the following constraint restricts a parameter to set of valid values:
public class ValuesConstraint : IRouteConstraint
{
private readonly string[] validOptions;
public ValuesConstraint(string options)
{
validOptions = options.Split('|');
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(parameterName, out value) && value != null)
{
return validOptions.Contains(value.ToString(), StringComparer.OrdinalIgnoreCase);
}
return false;
}
}
The following code shows how to register the constraint:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
var constraintsResolver = new DefaultInlineConstraintResolver();
constraintsResolver.ConstraintMap.Add("values", typeof(ValuesConstraint));
routes.MapMvcAttributeRoutes(constraintsResolver);
}
}
Now you can apply the constraint in your routes:
public class TemperatureController : Controller
{
// eg: temp/celsius and /temp/fahrenheit but not /temp/kelvin
[Route("temp/{scale:values(celsius|fahrenheit)}")]
public ActionResult Show(string scale)
{
return Content("scale is " + scale);
}
}
In my opinion, this isn't great design. There are no judgments about what URL you intended and no specificity rules when matching unless you explicitly set them yourself. But at least you can get your URLs looking the way you want. Hopefully your constraint list isn't too long. If it is, or you don't want to hard-code the route string parameter and its constraints, you could build it programmatically outside the action method and feed it to the Route attribute as a variable.
I am using Breeze with much success in my SPA, but seem to be stuck when trying to return parent->child data in a single query by using expand().
When doing a single table query, the $type in the JSON return is correct:
$type: MySPA.Models.Challenge, MySPA
However if I use expand() in my query I get the relational data, but the $type is this:
System.Collections.Generic.Dictionary 2[[System.String, mscorlib],[System.Object, mscorlib]]
Because of the $type is not the proper table + namespace, the client side code can't tell that this is an entity and exposes it as JSON and not a Breeze object (with observables, entityAspect, etc.).
At first I was using my own ContextProvider so that I could override the Before/After saving methods. When I had these problems, I reverted back to the stock EFContextProvider<>.
I am using EF5 in a database first mode.
Here's my controller code:
[BreezeController]
public class DataController : ApiController
{
// readonly ModelProvider _contextProvider = new ModelProvider();
readonly EFContextProvider<TestEntities> _contextProvider = new EFContextProvider<TestEntities>();
[HttpGet]
public string Metadata()
{
return _contextProvider.Metadata();
}
[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
[HttpGet]
public IQueryable<Challenge> Challenges()
{
return _contextProvider.Context.Challenges;
}
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _contextProvider.SaveChanges(saveBundle);
}
public IQueryable<ChallengeNote> ChallengeNotes()
{
return _contextProvider.Context.ChallengeNotes;
}
}
Here's my BreezeWebApiConfig.cs
public static void RegisterBreezePreStart()
{
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "BreezeApi",
routeTemplate: "breeze/{controller}/{action}"
);
}
Is there a configuration setting that I am missing?
Did you try "expanding" on server side? Is it needed to do expand on client side? I tried to do expand before but failed for me as well, did some research and decided I'd rather place it on server:
[HttpGet]
public IQueryable<Challenge> ChallengesWithNotes()
{
return _contextProvider.Context.Challenges.Include("ChallengeNotes");
}
This should be parsed as expected. On client side you would query for "ChallengeNotes" instead of "Challenges" and you wouldn't need to write expand part.
I strongly suspect that the problem is due to your use of the [Queryable] attribute.
You must use the [BreezeQueryable] attribute instead!
See the documentation on limiting queries.
We are aware that Web API's QueryableAttribute has been deprecated in favor of EnableQueryAttribute in Web API v.1.5. Please stick with BreezeQueryable until we've had a chance to write a corresponding derived attribute for EnableQuery. Check with the documentation for the status of this development.
I have an existing application that sends a Request with a parameter named 'filters'. The 'filters' parameter contains a string that is JSON encoded. Example:
[{"dataIndex":"fieldName", "value":"fieldValue"}, {"dataIndex":"field2", "value":"value2"}].
Using ServiceStack, I would like to bind this as a property on a C# object (class Grid). Is there a preferred method to handle this? Here are the options I can think of. I don't think either 'feel' correct.
Option 1:
I do have a 'ServiceModel' project and this would create a dependency on it which I don't really like.
In AppHost.Configure() method add
RequestBinders[typeof(Grid)] => httpReq => {
return new Grid() {
Filters = new ServiceStack.Text.JsonSerializer<IList<Filter>>().DeserializeFromString(httpReq.QueryString["filters"])
}
}
Option 2:
Seems kind of 'hacky'
public class Grid
{
private string _filters;
public dynamic Filters {
get
{
ServiceStack.Text.JsonSerializer<IList<Filter().DeserializeFromString(_filters);
}
set
{
_filters = value;
}
}
}
You can send Complex objects in ServiceStack using the JSV Format.
If you want to send JSON via the QueryString you can access it from inside your Service of Request filters with something like:
public object Any(Request req) {
var filters = base.Request.QueryString["Filters"].FromJson<List<Filter>>();
}
Note: Interfaces on DTOs are bad practice.