URL Encoding being lost before processing - ASP.net - asp.net

I am building a web-store that uses URL encoding extensively.
I have a list of Departments & Categories in my database which I use to generate the links. These are, of course, URL encoded before they are sent.
Some Typical Links are...
/MySite/Store/Countertop+Equipment/Can+Openers.aspx
/MySite/Store/Dinnerware.aspx
/MySite/Store/Kitchen/Pastry%2f+Decorating.aspx
In my HTTPHandler I call app.Request.Path to obtain the current path. The string returned by this call is no longer URL encoded which is making it impossible for me to parse correctly.
Once the URL encoding is lost
/MySite/Store/Kitchen/Pastry%2f+Decorating.aspx becomes
/MySite/Store/Kitchen/Pastry/Decorating.aspx.
This is obviously breaking the method that converts the URL to a QueryString.
Anyone know how to fix this?
Here is the core of my HTTPHandler
public void Init(System.Web.HttpApplication app)
{
app.BeginRequest += new EventHandler(Application_BeginRequest);
}
private void Application_BeginRequest(object sender, EventArgs e)
{
System.Web.HttpApplication app = (System.Web.HttpApplication)sender;
string realUrl = GetRealUrl(app.Request.Path);
if (!String.IsNullOrEmpty(realUrl))
app.Context.RewritePath(realUrl, false);
}
I really appreciate your help!

You cannot use Request.Url (including Url..PathAndQuery, AbsolutePath etc) as its OriginalString is already decoded.
So there is no point to use Request.Url at all and you can try to play with following:
Request.AppRelativeCurrentExecutionFilePath
Request.CurrentExecutionFilePath
Or in a worst-case scenario you'll need to parse the Url:
[Test]
public void RewriteProoveOfConcept() {
var path = #"/MySite/Store/Kitchen/Pastry%2f+Decorating.aspx";
var res = Regex.Replace(path, #"/(.+)/(.+)/(.+)/(.+)\.aspx", #"/$1/YourPage.aspx?category1=$2&category2=$3&category3=$4");
Assert.AreEqual(#"/MySite/YourPage.aspx?category1=Store&category2=Kitchen&category3=Pastry%2f+Decorating", res);
}
This shows how you can get the URL:
/MySite/YourPage.aspx?category1=Store&category2=Kitchen&category3=Pastry%2f+Decorating
from:
/MySite/Store/Kitchen/Pastry%2f+Decorating.aspx
Additionally consider using Routing instead of UrlRewrite.
Cheers,
Dmitriy.

Try the AbsolutePath or PathAndQuery properties on the Request object. Both of them should maintain the url encoding.

You can UrlEncode the URL before parsing it. Or better yet, keep URL's non-encoded in database. You don't even need to encode them if you use HyperLink control.

It turns out that the issue is occurring in IIS before .Net even gets its hands on the request. It appears that this is a dead end.
An additional word of warning is that my IIS test server (XP) was rejecting requests containing encoded amperstands as a security risk and could not be persuaded to cooperate with anything short of a registry edit. Not sure if this goes for all versions, but even if a server variable can be retrieved this seems like another good reason to use a different tactic.
Here is the follow-up question with the accepted solution-
ASP.Net URL Encoding

Related

HTTP get request won't submit with a URL encoded parameter

I'm currently writing an ASP.NET Core web API that has an action with a encrypted value as a parameter.
I'm trying to test this action and the URL won't even submit in the web browser, at first I thought it could be due to the URL being too long but I've found this answer and my URL is well below the 2000 character limit. I've changed the parameter to a trivial string ("hello") and it submits fine and runs the code. I've tried in both Edge and IE11 whilst debugging my application, in Edge nothing happens at all, in IE11 I get a message saying:
Windows cannot find 'http://localhost:5000/api/...' Check the spelling and try again
In either case the code in the application doesn't execute (I've put a breakpoint on the first line of the controllers constructor which isn't being hit).
I've included an example of one of the URLs that isn't working below, as well as the code I'm using to generate the encrypted string, it uses HttpUtility.UrlEncode to convert the encrypted byte[] array to a string.
Example URL (one that doesn't work):
http://localhost:5000/api/testcontroller/doaction/%95%d6%f8%97%84K%1f%d4%40P%f0%8d%de%27%19%ed%ffAR%9c%c6%d4%b1%83%1e%9fX%ce%9b%ca%0e%d4j%d3Rlz%89%19%96%5dL%b1%16%e9V%14u%c7W%ee%89p%3f%f7%e6d%60%13%e5%ca%00%e9%a2%27%cb%d3J%94%a6%e1%b9%9c%914%06y%7e%0bn%ce%00%e5%7d%98b%85c%fa6m%7d%f7%f1%7b8%26%22%5e%1et%5e%10%0c%05%dd%deFAR%bb%93L%b9-W%e1K%82%d8%cc8%ce%e0%0c%2b%bc%19
Action:
[HttpGet("[action]/{encrypted}")]
public string DoAction(string encrypted)
{
return "Executed";
}
Generate encrypted string:
private string GenerateEncryptedString()
{
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider();
byte[] data = HttpUtility.UrlDecodeToBytes("AHMW9GMXQZXYL04EYBIW");
byte[] encryptedData = rsaProvider.Encrypt(data, true);
string encryptedString = HttpUtility.UrlEncode(encryptedData);
return encryptedString;
}
Not sure if I'm going wrong in my methodology for converting the encrypted data to a string but I would appreciate any feedback on how to fix this issue.
I think you should try to pass this data in the query string and not in the location (path) part of the url (some characters may be forbidden in paths as a security layer), so add a ?data= before the encoded data.
http://localhost:5000/api/testcontroller/doaction/?data=%95%d6%f8%97%84K%1f%d4%40P%f0%8d%de%27%19%ed%ffAR%9c%c6%d4%b1%83%1e%9fX%ce%9b%ca%0e%d4j%d3Rlz%89%19%96%5dL%b1%16%e9V%14u%c7W%ee%89p%3f%f7%e6d%60%13%e5%ca%00%e9%a2%27%cb%d3J%94%a6%e1%b9%9c%914%06y%7e%0bn%ce%00%e5%7d%98b%85c%fa6m%7d%f7%f1%7b8%26%22%5e%1et%5e%10%0c%05%dd%deFAR%bb%93L%b9-W%e1K%82%d8%cc8%ce%e0%0c%2b%bc%19

serving images by id with imageresizer.net

I keep a mapping in database between an ID and the filename of the image uploaded on server.
This is because I need to refer to images in HTML using an ID and not the actual filename on the disk (if image is replaced, it would be hard to have a logic which replaces the references to the new image).
So the solution I see is to have a handler which is getting the virtual image path based on the ID, and then redirects to this URL. This should make the ImageResizer.net to still work.
public class Image : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
int id;
if (int.TryParse((string)context.Request.QueryString["id"], out id))
{
string path = ... // get filename from database by id and append any other query params used by imageresizer.net
context.Response.Redirect(path);
}
else
{
// return error response
}
}
}
Referencing the image:
<img src="/Image.ashx?id=1&w=100" />
My question is, am I doing this right?
I am thinking about issues like caching on the client.
Also, doing an extra request with Redirect (but this one is really the least I am concerned about now).
It works, but the redirect adds significant latency. If you don't have control over the HTML (which is where the URL should change when the file is changed), then your options are limited.
If you can work with your caching headers so the redirect isn't needed, you can use the Config.Current.Rewrite event provided by ImageResizer, or use a generic URL Rewriting solution to simply parse and lookup the filename.
This will eliminate a round-trip to the server - and remember, redirects are cached, so you'll have the same problem unless you solve your issue with cache directives.
Also, if you're hitting the DB for each request, make sure there's some kind of caching in place.

Create HTTP POST method in ASP.NET which accepts CGI variables

I have an ASP.NET (.NET v4) web application running on IIS 7.5. I have a 3rd party which wants to pass information to my system. They support passing this information using HTTP POST, the information they provide is:
"This method simply calls a script on your server and passes each
field as a CGI variable. When you have received the data your server
should return a '1' on a line by itself to indicate success. Anything
else will generate an error on our server which will be investigated.
To set up this delivery method we need a URL to post to. We can use
HTTP or HTTPS."
My web application currently implements many WCF services but as I don't know what the variables passed in will be I cannot define a specific contract. Can I create a normal aspx page which they can post to and then read each of the parameters passed and do the appropriate processing.
If I do this how do I send back a line containing '1'?
Do I need to do anything else to make this HTTP POST compatible.
The last time I had to tackle a similar situation, i did it using a standard ASPX page, and it all worked quite well.
In my case the output was XML, so I had to make sure that I changed the output mime type to match "text/xml" in my case.. "text/plain" I would guess in yours..
Anyway, C# sharp code below, and make sure that your ASPX file has ONLY the very top line in, that is:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="register.aspx.cs" Inherits="myservices.register" ContentType="text/xml" %>
and nothing else, no carriage returns or anything.
Then do all your work in the code behind:
protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
Response.ContentType = "text/plain";
//Get your CGI variables here... you will have to get them to tell you what to expect
string myparam = (string)Request.QueryString["myparam"];
//do what ever you need here with your variables
Response.Write("1");
Response.End();
}// End page load handler
If you need to follow the one with a carriage return, then i believe you can use the carriage return property in the system.environment object, but I've not got doc's to hand to look it up. That should however get you started.
The MOST important thing to remember is to make sure NOTHING is output from the aspx, not even a carriage return.
I've previously written an article on my Blog about how to use this method for producing phone directories for Cisco-IP phones if you want to read it. You can find it here: http://shawtyds.wordpress.com/2009/09/26/cisco-ip-phone-directories-using-c/

ASPX URL is broken & Streaming WebService

I'm attempting to create a streaming webservice, unfortunally i even lack its concept overall. My idea is to have a method which will return to me a string with the value of the URL to the streaming page.
I've tried many different ways to do this, but no one of them worked; I tried using DownloadString, even writting the raw URL, but i always had errors so i found one way to just make it happen:
[WebMethod]
public string WatchMedia(string title)
{
Global.Media = title;
Streaming str = new Streaming(); //Streaming.aspx
return str.GetURL();
}
Okay so, in my aspx.cs i included this:
internal string GetURL()
{
return HttpContext.Current.Request.Url.AbsoluteUri.ToString();
}
Don't really ask me about the 'internal', i'm so tired of trying different ways to get this to work that i just go along with that VS builds for me.
That does give me the URL i thought i wanted, BUT, it doesn't work, why? Because it says, give or take (directly translated):
The request format is not recognized for the unexpectedly terminated URL in /WatchMedia
WatchMedia is the name of my method as seen above.
Now, beside's hoping someone can give me a straight answer as to what ridiculous sin am i hurting my self with here, i'd like to know if this is the way for a streaming webservice to work? I can't seem to find any real information about video streaming webservices over the www, not even Google will tell me!
If you ever have the same problem, just forget creating an object of the aspx page, and get the URL raw, by running the page and copying it, then all you have to do is change the localhost Port, which you can get from HttpContext.

How to get WebResource.axd querystring in correct case?

I am getting the css files for minifying and compressing from QueryString["path"] everything works correctly for my own css files like main.css. But when I try to acess the webresource files I receive a 500 error. The parameter which comes after the webresource.axd is case sensitive and I receive it from QueryString["path"] lowercase.
This is what I get from QueryString["path"] :
http://localhost/test/webresource.axd?d=-phgrn6r6zgehvbi697-bxvkl_gidnplxpdeukz5kncgr9hvnfvttpgykwyw05cda-nymtz9od_bbww3ynzxha2&t=633789305460522066
The above link generate error : CryptographicException: Padding is invalid and cannot be removed.
This is what the correct link look like :
http://localhost/test/WebResource.axd?d=-pHGRn6r6ZGehvBI697-BxVKl_GIdNPlxPdEUKZ5KNcGR9hvnfVtTpgyKwYw05cDa-NymTz9OD_bBwW3ynZXhA2&t=633789305460522066
The only difference is in the case. CryptographicException seem to be common but even setting machineKey didn't fixed the problem. Any hint on how could I get the the webresource.axd in the original case?
EDIT
Code was requested :
public void ProcessRequest(HttpContext context) {
Control c = new Control();
string root = context.Request.Url.GetLeftPart(UriPartial.Authority);
string path = context.Request.QueryString["path"];
string content = string.Empty;
if (!string.IsNullOrEmpty(path)) {
if (context.Cache[path] == null) {
List<string> dependencies = new List<string>();
string[] styles = path.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (string style in styles) {
content += RetrieveStyle(root + c.ResolveUrl(style)) + Environment.NewLine;
dependencies.Add(context.Server.MapPath(style));
}
content = StripWhitespace(content);
context.Cache.Insert(path, content, new CacheDependency(dependencies.ToArray()), Cache.NoAbsoluteExpiration, new TimeSpan(DAYS_IN_CACHE, 0, 0, 0));
}
}
}
It crashes in RetreiveStyle when I call :
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
The culprit looks like the code that is generating the “path” querystring csv or some hardware or filter between that source and your handler.
If the source of handler request is a browser what does the handler url look like through view source or firebug? Is it lowercase already?
Working forward from that, do you have any modules etc registered in you IIS pipeline?
I do not have an answer but we have experienced a similar problem and I have a few things to add, which could help identifying the issue.
So, here it goes:
We have an iHTTPHandler (lets call it Login.ashx) that accepts a GET request, which contains a token in base64 format.
The token is then decrypted using Rijndael algorithm.
This process is working most of the time, however, in the last month we had several requests that failed due to System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed. error. This error is raised in our case when a token (base64 string) is in lowercase and cannot be decrypted.
After going through logs and activity records I can see that a particular user would attempt to come to our side via Login.ashx and the request would fail due to the error in question. The whole querystring of the request (there is more than just token) including names and values is in lowercase. Then the same user would attempt a login a few minutes later and is able to get in because the querystring was not transformed to lower case.
So, I have a feeling that the issue could be browser related. I am not sure if proxy could affect this.
Additional info:
There is no browser information captured in the server variables.
ALL_HTTP and ALL_RAW variables have almost no data:
ALL_HTTP HTTP_CACHE_CONTROL: no-cache HTTP_HOST:our server name
ALL_RAW Cache-Control: no-cache Host: our server name
There is also no HTTP_REFFERER.
I have tried to replicate this issue with different browsers (Safari3, Chrome1, Opera9.2, IE6,7,8, Firefox3) with no luck.
We have a web farm with 10 servers configured identically (at least I hope they are)
I will add more info if I get any progress.

Resources