Reverse function of HttpUtility.ParseQueryString - asp.net

.Net's System.Web.HttpUtility class defines the following function to parse a query string into a NameValueCollection:
public static NameValueCollection ParseQueryString(string query);
Is there any function to do the reverse (i.e. to convert a NameValueCollection into a query string)?

System.Collections.Specialized.NameValueCollection does NOT support this, but a derived internal class System.Web.HttpValueCollection DOES (by overriding ToString()).
Unfortunately (being internal) you cannot instantiate this class directly, but one is returned by HttpUtility.ParseQueryString() (and you can call this with String.Empty, but not Null).
Once you have a HttpValueCollection, you can fill it from your original NameValueCollection by calling Add(), before finally calling ToString().
var nameValueCollection = new NameValueCollection {{"a","b"},{"c","d"}};
var httpValueCollection = System.Web.HttpUtility.ParseQueryString(String.Empty);
httpValueCollection.Add(nameValueCollection);
var qs = httpValueCollection.ToString();
nameValueCollection.ToString() = "System.Collections.Specialized.NameValueCollection"
httpValueCollection.ToString() = "a=b&c=d"

A NameValueCollection has an automatic ToString() method that will write all your elements out as a querystring automatically.
you don't need to write your own.
var querystringCollection = HttpUtility.ParseQueryString("test=value1&test=value2");
var output = querystringCollection.ToString();
output = "test=value1&test=value2"

I found that a combination of UriBuilder and HttpUtility classes meets my requirements to manipulate query parameters. The Uri class on its own is not enough, particularly as its Query property is read only.
var uriBuilder = new UriBuilder("http://example.com/something?param1=whatever");
var queryParameters = HttpUtility.ParseQueryString(uriBuilder.Query);
queryParameters.Add("param2", "whatever2");
queryParameters.Add("param3", "whatever2");
uriBuilder.Query = queryParameters.ToString();
var urlString = uriBuilder.Uri.ToString();
The above code results in the URL string: http://example.com/something?param1=whatever&param2=whatever2&param3=whatever2
Note that the ToString() goes via a Uri property, otherwise the output string would have an explicit port 80 in it.
It's nice to be able to do all this using framework classes and not have to write our own code.

I don't think there is a built in one, but here is an example of how to implement http://blog.leekelleher.com/2008/06/06/how-to-convert-namevaluecollection-to-a-query-string/

Here are 2 very useful functions that I use all the time:
private string GetQueryStringParameterValue(Uri url, string key)
{
return HttpUtility.ParseQueryString(url.Query.TrimStart('?'))[key];
}
private Uri SetQueryStringParameterValue(Uri url, string key, string value)
{
var parameters = HttpUtility.ParseQueryString(url.Query.TrimStart('?'));
parameters[key] = value;
var uriBuilder = new UriBuilder(url) { Query = parameters.ToString() };
return uriBuilder.Uri;
}

Related

Unable to rectify VeraCode CWE ID 918 - (SSRF) in ASP.NET

Long story short, no matter what I try VeraCode continues to flag 8 lines of my code as flaws with CWE 918. This is old code so I'm not sure why it's suddenly being flagged.
Here's an example [offending] method with the flagged line in bold
public virtual async Task<HttpResponseMessage> Put(string controller = "", Dictionary<string, object> parameters = null, object body = null)
{
if (string.IsNullOrWhiteSpace(ApiBaseUrl)) return null;
HttpResponseMessage response = null;
using (var client = GetHttpClient())
{
client.BaseAddress = new Uri(ApiBaseUrl);
if (!string.IsNullOrEmpty(Token)) client.DefaultRequestHeaders.Add("Token-Key", Token);
if (!string.IsNullOrEmpty(DeviceId)) client.DefaultRequestHeaders.Add("DeviceId", DeviceId);
var url = GenerateUrl(controller, parameters);
var requestBody = GeneratedHttpContent(body);
if (requestBody == null) requestBody = new StringContent("");
**response = await client.PutAsync(url, requestBody);**
await LogError(response);
return response;
}
}
Here's my proposed fix that utilized an extension method to validate the URL
var url = GenerateUrl(controller, parameters);
var requestBody = GeneratedHttpContent(body);
if (requestBody == null) requestBody = new StringContent("");
**if (url.IsValidUrl())
{
response = await client.PutAsync(url, requestBody);
}
else
{
response = new HttpResponseMessage(HttpStatusCode.BadRequest);
}**
await LogError(response);
return response;
Here is the extension method with a VeraCode attribute
[RedirectUrlCleanser]
public static bool IsValidUrl(this string source)
{
return Uri.TryCreate(source, UriKind.RelativeOrAbsolute, out Uri uriResult) && Uri.IsWellFormedUriString(source, UriKind.RelativeOrAbsolute);
}
I can have VeraCode automatically mitigate based on the attribute, but our client will be performing their own scan and certainly won't have that setting enabled.
Any ideas on how I can resolve this would be appreciated.
The true source of the flaw is inside of your GenerateUrl method which is unfortunately not shown, but here is the general idea of what the Veracode is complaining about.
For CWE ID 918 it is hard to make Veracode recognize your fix unless you have static URL. You need to validate all your inputs that become parts of your request URL.
Below is what I found at the Veracode site:
https://community.veracode.com/s/question/0D52T00004i1UiSSAU/how-to-fix-cwe-918-veracode-flaw-on-webrequest-getresponce-method
The complete solution existed only for the case where you have single or some small number of possible input values (white list):
public WebResponse ProxyImage(string image_host, string image_path)
{
string validated_image_host = AllowedHosts.Host1;
if (image_host.Equals(AllowedHosts.Host2))
validated_image_host = AllowedHosts.Host2;
string validated_image = AllowedImages.Image1;
if (image_path.Equals(AllowedImages.Image2))
validated_image = AllowedImages.Image2;
string url = $"http://{validated_image_host}.example.com/{validated_image}";
return WebRequest.Create(url).GetResponse();
}
If the set of possible valid values is too large for that kind of validation then you need to fix the flaw by implementing dynamic validation of inputs using regular expressions. Unfortunately, Veracode is not smart enough to recognize that kind of fix, so "mitigation by design" is still required.
public WebResponse ProxyImage(string image_host, string image_path)
{
var image_host_regex = new System.Text.RegularExpressions.Regex("^[a-z]{1,10}$");
if (!image_host_regex.Match(image_host).Success)
throw new ArgumentException("Invalid image_host");
var image_path_regex = new System.Text.RegularExpressions.Regex("^/[a-z]{1,10}/[a-z]{1,255}.png$");
if (!image_path_regex.Match(image_path).Success)
throw new ArgumentException("Invalid image_host");
string url = $"http://{image_host}.example.com/{image_path}";
return WebRequest.Create(url).GetResponse();
}
Another way to fix this issue (which is kind of a hack) is to append your query string parameters in the baseAddress of the HttpClient, this way the veracode will not treat it like a flaw.
Here is how the solution would look like
public async Task<Data> GetData(string input)
{
try
{
var httpClient = new HttpClient();
//Appended the parameter in base address to
//to fix veracode flaw issue
httpClient.BaseAddress = new Uri($"https://someurl.com/somefunction/{input}");
//passing empty string in GetStringAsync to make sure
//veracode doesn't treat it like modifying url
var content = await httpClient.GetStringAsync("");
return JsonConvert.DeserializeObject<Data>(content);
}
}

Can I disable model binding and use the raw request body in an action in dotnet core?

I want to setup an endpoint for testing webhooks from third parties. Their documentation is uniformly poor and there is no way ahead of time to tell exactly what I will be getting. What I've done is setup an ApiController that will just take a request and add a row to a table with what they are sending. This lets me at least verify they are calling the webhook, and to see the data so I can program to it.
// ANY api/webook/*
[Route("{*path}")]
public ActionResult Any(string path)
{
string method = Request.Method;
string name = "path";
string apiUrl = Request.Path;
string apiQuery = Request.QueryString.ToString();
string apiHeaders = JsonConvert.SerializeObject(Request.Headers);
string apiBody = null;
using (StreamReader reader = new StreamReader(Request.Body))
{
apiBody = reader.ReadToEnd();
}
Add(method, name, apiUrl, apiQuery, apiHeaders, apiBody);
return new JsonResult(new { }, JsonSettings.Default);
}
This works great, except for this new webhook I am usign that posts as form data so some middleware is reading the body and it ends up null in my code. Is there any way to disable the model processing so I can get at the request body?
You could actually use model binding to your advantage and skip all that stream reading, using the FromBody attribute. Try this:
[Route("{*path}")]
[HttpPost]
public ActionResult Any(string path, [FromBody] string apiBody)

Converting created document result to POCO

I have the following code that calls DocumentDB and creates a new Employee document. How do I then convert the result to Employee document again? Basically, I want to capture the created document and convert it to Employee object.
var result = await client.CreateDocumentAsync(collection.SelfLink, employee);
if(result.StatusCode == System.Net.HttpStatusCode.Created)
{
Employee emp = result.Resource; // How do I convert the result to Employee object here?
}
You can do a dynamic cast like this:
Employee emp = (dynamic)result.Resource;
I wrote an extension method to do this:
public static async Task<T> ReadAsAsync<T>(this Document d)
{
using (var ms = new MemoryStream())
using (var reader = new StreamReader(ms))
{
d.SaveTo(ms);
ms.Position = 0;
return JsonConvert.DeserializeObject<T>(await reader.ReadToEndAsync());
}
}
Then you can use it like
Document d;
var myObj = await d.ReadAsAsync<MyObject>();
(Copying over Andrew Davis's answer, from the DocumentDB MSDN forums, for the stackoverflow community)
The simplest way would be to have your Employee class inherit from Document, and then cast result.Resource to Employee. If you don't want to inherit from Document, you could also define an explicit cast between Document and Employee.
Having the Employee class inherit from Document should work out-of-the-box if the names of the members of your Employee class match the names of the corresponding properties of the JSON representation.
Defining your own type conversion gives you more control, and might look something like this:
public static explicit operator Employee(Document doc)
{
Employee emp = new Employee();
emp.Name = doc.GetPropertyValue<string>("employeeName");
emp.Number = doc.GetPropertyValue<int>("employeeNumber");
/* and so on, for all the properties of Employee */
return emp;
}
This would define an explicit cast from Document to Employee. You'll have to make sure the GetPropertyValue strings (and type arguments) match your JSON properties.
Here's a a synchronous extension method that doesn't silently miss properties like the (dynamic) cast method can. Uses recent .NET Core features Span and System.Text.Json for performance.
Usage:
Document doc; // source Document
MyType converted = doc.ConvertTo<MyType>();
Implementation:
public static T ConvertTo<T>(this Document item)
{
using var stream = new MemoryStream();
item.SaveTo(stream);
var bytes = new ReadOnlySpan<byte>(stream.GetBuffer()).Slice(0, (int)stream.Length);
return JsonSerializer.Deserialize<T>(bytes);
}

Web Service is not returning JSON

I know many times this question has been posted over here. But i am not able to find solution for my problem.
I have create one web service and i have set method return type as JSON but method still returns XML.
Here is my method :
[WebMethod(Description = "LoginMethod")]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string doLogin(string UserName, string Password)
{
LoginSuccess objSuccess = new LoginSuccess();
UserInfo objInfo = new UserInfo();
objSuccess.success = "true";
objInfo.Token = "token";
objInfo.type = "usertype";
objInfo.username = "username";
objInfo.userid = "userid";
objSuccess.response = objInfo;
clsJSON objJSON = new clsJSON();
loginResponse = objJSON.ToJSON(objSuccess);
return loginResponse;
}
Here is my response :
<string>{"success":"true","response":{"Token":"token","username":"username","userid":"userid","type":"usertype"}}</string>
But i want this as :
{"success":"true","response":{"Token":"token","username":"username","userid":"userid","type":"usertype"}}
I am calling this method from that page which web service giving us to test method. Request method is HttpPost.
Please suggest me for this.
The problem is that you've either not specified or used the wrong accept request header. It should be application/json. Without the relevant javascript code used to fetch data in your question it's not possible to say what exactly you should put where though.

ASP.NET WebMethod Returns JSON wrapped in quotes

I have an asp.net page with a WebMethod on it to pass JSON back to my javascript.
Bellow is the web method:
[WebMethod]
public static string getData(Dictionary<string, string> d) {
string response = "{ \"firstname\": \"John\", \"lastname\": \"Smith\" }";
return response;
}
When this is returned to the client it is formatted as follows:
{ \"d\": \"{ \"firstname\": \"John\", \"lastname\": \"Smith\" }\" }
The problem is the double quotes wrapping everything under 'd'. Is there something I've missed in the web method or some other means of returning the data without the quotes? I don't really want to be stripping it out on the client everytime. Also I've seen other articles where this doesn't happen.
Any help would be appreciated thanks.
I assume that you want to return the JSON representation of the object
{
firstname:"John",
lastname:"Smith"
}
but your method signature is returning a string. The ASP.Net framework serialisation is correctly serialising the string response. Put another way, if your function was
string response = "foo";
return response;
You would not be surprised if the output was
{"d":{"foo"}}
It just happens that response has double quotes that need to be escaped.
You obviously just want to get at the object. You have 2 options: -
1) use eval in your javascript to turn the string into an object e.g.
function onSuccessCallback(retval) {
var obj = eval(retval.d);
}`
2) or (and this is my prefered solution) have your method return an actual object and let the JSON serialisationof the framework do the heavy lifting for you
[WebMethod]
public static object getData(Dictionary<string, string> d) {
var response = new { firstname = "John", lastname="Smith" };
return response;
}
You will see that this generates the response that you probably originally expected (e.g.
{"d":{"firstname":"John", "lastname":"Smith"}}
Actually this entire issue exists because you're trying to out-think ASP.Net web services. You need to setup a class for your data to be returned and use that class (or List(of YourClass)) to queue up results and return them.
A great article explaining all this (a very common pitfall) is: http://encosia.com/asp-net-web-services-mistake-manual-json-serialization/
I had a similar issue with my code. I was trying to return an XmlDocument as JSON to a calling script but returning XmlDocument from the WebService returned an empty set of arrays (as XmlDocument is NOT serializable!).
If i set the ScriptService with the attribute ResponseFormat.JSON then my JSON was double-escaped.
The way to out-fox ASP.NET is to tell ASP.NET that you're returning XML and then it won't double-escape your JSON ;-)
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public String MyJSONWebService(String sParam1, String sParam2, String sParam3)
{
... do stuff.....
XmlDocument oXMLDocument = new XmlDocument();
oXMLDocument.LoadXml(sXML);
sJSON = JsonConvert.SerializeXmlNode(oXMLDocument.SelectSingleNode("autnresponse"));
return sJSON;
}
I know it's a hack but .....

Resources