How to drop/discard a Request in ASP.NET? - asp.net

I'm trying to figure out how to drop/discard a request, I'm basically trying to implement a blocked list of IPs in my app to block spammers and I don't want to return any response (just ignore the request), is this possible in ASP.NET?
Edit: Some of the answers suggest that I could add them in the firewall, while this will certainly be better it's not suitable in my case. To make a long story short, I'm adding a moderation section to my website where moderators will check the posts awaiting moderation for spam (filtered by a spam fitler), I want the IP of the sender of some post to be added to the list of blocked IPs once a post is marked as spam by the moderator, this is why I wan to do it in the application.
Edit: Calling Response.End() returns a response to the user (even though it's empty), the whole purpose of my question was how not to return any response. Is this possible (even out of curiosity)? There's also Response.Close() which closes the socket but it sends notification (in TCP/IP) when it does this, I just wan to ignore as it if was never received (i.e. send nothing to the user)
Thanks

For this type of thing, I would go with an HTTP Module as opposed to doing this with a handler or a page.
Why use a module instead of a handler? An HTTP Module is called earlier in the request pipeline. For these type of blacklisted requests, you want to drop the request as early and fast as possible. This means the earlier in the request you can drop the request, the better.
You can read a little more about Modules vs Handlers here.

Maybe you could use
Response.Clear();
Response.End();

My first thought was what John suggested. The most ideal solution would be to add those IPs to the list of blocked IPs in your firewall if you have access to it, that way your application isn't having to do any processing at all.

EDIT: This might be better implemented as an HTTPModule instead of a handler, but the basic idea holds true. See http://www.kowitz.net/archive/2006/03/08/ihttpmodule-vs-ihttphandler.aspx for more details
You could probably do this using an httphandler, that way you won't have to worry about checking for this in your application code - its handled before your application is even executed.
Psudo code - not tested
class IgnoreHandler : IHttpHandler
{
#region IHttpHandler Members
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.Clear();
context.Response.StatusCode = 401;
context.Response.Status = "Unauthorized";
context.Response.End();
}
#endregion
}
Obviously, if you want it to return HTTP 200 (OK) and a blank page, just remove the two lines referring to the StatusCode and Status.
And then register it in web.config
<httpHandlers>
<add verb="*"
path="*"
validate="false"
type="MyNamespace.IgnoreHandler, MyAssembly" />
</httpHandlers>

Here you go:
public class RequestDropper : IHttpModule
{
public void Dispose()
{
throw new NotImplementedException();
}
public void Init(HttpApplication context)
{
context.BeginRequest += Context_BeginRequest;
}
public void Context_BeginRequest(object sender, EventArgs e)
{
var request = ((HttpApplication)sender).Context.Request;
if (todayIAmNotInAMoodToProcessRequests)
{
request.Abort();
}
}
}
Hope this saves you some time

I would suggest the best solution is not to give a specific "no response" but to give a more discouraging standard http error message. Whenever I am attempting to discourage unauthorised users I issue a page/url not found message as follows:
throw new HttpException(404, "File not found - " + Request.AppRelativeCurrentExecutionFilePath);
I think that this is very effective at convincing the person at the other end to give up and go away.

You may want to have a look at this http://www.angrypets.com/tools/rdos/, which does a similar thing to what you are talking about, for similar reasons, and is implemented as a module.

An other annoying but easy way to do it would be to Sleep the request for a discouraging amount of time before closing it.

AFAIK there is no way to outright drop a request without a response. You can keep the request spinning in ASP.NET with whatever thread sleeping technique you like but you're not making life better for your server that way.
The best way that I know of to achieve what you want is having a traffic manager like ZXTM close the request before it gets to the webserver at all.

Related

Asp.net session never expires when using SignalR and transport mode long polling

We have a web application that uses SignalR for its notification mechanism.The problem is when we are browsing our web application using IE ,SignalR uses Long Polling as its transport type thus sends back requests to our web server therefore Session never expires no matter how long the browser is idle.
We were thinking that maybe we could catch the requests in Global.asax and see if they were from SingalR and set the session timeout to the remaining time (Which I don't think it's a straightforward solution).
Is there any other solution the we are missing ?
The workaround I am currently using is an IHttpModule to check if the request is a Signalr request, if so remove the authentication cookie, this will prevent the ASP.net session timeout from being reset, so if your Session Timeout is 20min and the only requests are Signalr the users session will still timeout and the user will have to login again.
public class SignalRCookieBypassModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.PreSendRequestHeaders += OnPreSendRequestHeaders;
}
private bool IsSignalrRequest(string path)
{
return path.IndexOf("/signalr/", StringComparison.OrdinalIgnoreCase) > -1;
}
protected void OnPreSendRequestHeaders(object sender, EventArgs e)
{
var httpContext = ((HttpApplication)sender).Context;
if (IsSignalrRequest(httpContext.Request.Path))
{
// Remove auth cooke to avoid sliding expiration renew
httpContext.Response.Cookies.Remove(DefaultAuthenticationTypes.ApplicationCookie);
}
}
public void Dispose()
{
}
}
I feel this is a real hack solution so would love so other ideas to prevent session timeout renew when data is pushed to the client from the server, or a when javascript client polls an endpoint for data.
If you take a look at the description of the SignalR protocol I wrote a while ago you will find this:
» ping – pings the server
...
Remarks: The ping request is not really a “connection management request”. The sole purpose of this request is to keep the ASP.NET session alive. It is only sent by the the JavaScript client.
So, I guess the ping request is doing its job.
I here post #Simon Mourier's commented solution, with his approval, as a CW answer, as I find the suggested approach the most appropriate and less intrusive, as it just disables the Session for SignalR requests.
A positive side effect is that the request will be processed faster as the Session object doesn't need to be initiated and loaded.
It still uses a IHttpModule for the work, and the preferable place is likely the AcquireRequestState event (not personally tested yet though), or at an event raised earlier, before making use of the Session object.
Do note using this approach that one might need to test that the Session object is available before access any of its members or stored objects.
public class SignalRSessionBypassModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.AcquireRequestState += OnAcquireRequestState;
}
private bool IsSignalrRequest(string path)
{
return path.IndexOf("/signalr/", StringComparison.OrdinalIgnoreCase) > -1;
}
protected void AcquireRequestState(object sender, EventArgs e)
{
var httpContext = ((HttpApplication)sender).Context;
if (IsSignalrRequest(httpContext.Request.Path))
{
// Run request with Session disabled
httpContext.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Disabled);
}
}
public void Dispose()
{
}
}
Here is another completely different approach, simple, yet quite efficient.
Instead of relying on Session/Auth cookies to decide whether a user has timed out, use the Cache object. This have more or less no side effects and work just like if the user simply logged out.
By simply add this small snippet somewhere in the beginning of your web app code, where of course SignalR don't go, you will be able to check if the cache item is there and reinitiate it (with the same expiration time as the Session timeout is set), and if not, just do a logout and remove cookies/session variables.
if (Request.IsAuthenticated) {
if (Cache[Context.User.Identity.Name] == null) {
// Call you logout method here...,
// or just:
// - Sign out from auth;
// - Delete auth cookie
// - Remove all session vars
} else {
// Reinitiate the cache item
Cache.Insert(Context.User.Identity.Name,
"a to you usable value",
null,
DateTime.Now.AddMinutes(Session.Timeout),
Cache.NoSlidingExpiration,
CacheItemPriority.Default,
null
);
}
And within your user login method, you just add this, to create the cache item for the first time
// Insert the cache item
Cache.Insert(Context.User.Identity.Name,
"a to you usable value",
null,
DateTime.Now.AddMinutes(Session.Timeout),
Cache.NoSlidingExpiration,
CacheItemPriority.Default,
null
);
It's more stable and maintainable -in my view- to have your own "session like timeout" . Set your .NET session timeout to infinity since you'll not be using it and then create a global JavaScript counter (in your layout or master page) to track the time passing while the browser is idle (obviously setTimeout or setInterval every few seconds would do the trick). Make sure to have the counter reset on every web request (that should happen automatically since all JavaScript variables would reset). In case you have pages that depend on web services or Web API, make sure to reset your global JavaScript counter on every call. If the counter reaches your desired timeout without being reset, that means that the session is expired and you can logout the user. With this approach you'll have full control over the session lifetime which enables you to create a logout timer popup to warn the user that the session is about to expire. SignalR would perfectly fit with this approach since the JavaScript timer would keep ticking.

asp.net webservice handling gzip compressed request

I have an asp.net .asmx webservice written to handle requests from a third party tool. The third party tool makes an http POST request to the webservice to get user information. I'm using IIS7
Running Fiddler with "Remove All Encodings" checked, I can see the webservice call and and everything functions properly. If I uncheck "Remove All Encodings", the webservice call fails with a 400 Bad Request. The difference I see is that the header "Content-Encoding: gzip" is being removed by Fiddler and the content is being decompressed.
So, when the Content-Encoding header is removed and the content is decompressed, my webservice functions perfectly. When the header is present and the content is compressed, the webservice fails.
How can I either:
Configure my webservice to tell the client that it won't accept compressed requests (and hope that the third party tool respects that)
Decompress the content early in the asp.net handling
Modify my webservice to work with compressed data
Update: To be clear, I don't need to configure gzip encoding in the Response, I need to deal with a Request TO my webservice that is gzip encoded.
Update 2: The third-party tool is the Salesforce.com Outlook plugin. So, I don't have access to modify it and it is used by many other companies without trouble. It's got to be something I'm doing (or not doing)
Update 3: I found one post here that says that IIS does not support incoming POST requests with compressed data, it only supports compressed Responses. Can this still be true?
The simplest technique is to create an HttpModule that replaces the request filter. It is more reusable and avoids having a Global.asax. There is also no need to create a new decompress stream class as the GZipStream is ready for that. Here is the full code, that also removes the Content-Encoding: gzip that is not needed any more:
public class GZipRequestDecompressingModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += (sender, e) =>
{
var request = (sender as HttpApplication).Request;
string contentEncoding = request.Headers["Content-Encoding"];
if (string.Equals(contentEncoding, "gzip",
StringComparison.OrdinalIgnoreCase))
{
request.Filter = new GZipStream(request.Filter,
CompressionMode.Decompress);
request.Headers.Remove("Content-Encoding");
}
};
}
public void Dispose()
{
}
}
To activate this module, add the following section into your web.config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="AnyUniqueName"
type="YourNamespace.GZipRequestDecompressingModule, YourAssembly"
preCondition="integratedMode" />
</modules>
</system.webServer>
Since the 3rd party service is just sending you a POST, I do not think that it is possible to tell them not to send in compressed.
You could try to override GetWebRequest and decompress it on the way in
public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol
{
protected override WebRequest GetWebRequest(Uri uri)
{
base.GetWebRequest(uri);request.AutomaticDecompression = System.Net.DecompressionMethods.GZip;
return request;
}
}
GZIP compression is a function of the server.
If you're using IIS6, consult this link.
If you're using IIS7, you could use ISAPI_Rewrite to disable gzip. See this link.
That said, because gzip is a function of IIS, you really shouldn't need to do anything "special" to get it to work with a web service (IIS should handle decompressing and compressing requests). Hopefully this info will get you further down the road to troubleshooting and resolving the issue.
I am not sure that IIS supports decompressing incoming requests, so this might have to be done further down the pipe.
Shiraz's answer has the potential of working and it would be the first thing I would try.
If that doesn't work you might consider switching your server .asmx service to WCF, which while a bit more difficult to setup it also gives more flexibility.
On the WCF side there are two things I can suggest. The first is quite easy to implement and is based on setting the WebRequest object used by WCF to automatically accept compression. You can find the details here. This one is the WCF equivalent to the solution proposed by Shiraz.
The second is more complicated, since it involves creating Custom Message Encoders, but if none of the above methods work, this should solve the problem. Creating a message compression encoder is described here. You might also want to check the answer in here which presents a sample config for the message encoder.
Please let me know if this helped or if you need more help.
I've found a partial answer here.
class DecompressStream : Stream
{
...
public override int Read(byte[] buffer, int offset, int count)
{
GZipStream test = new GZipStream(_sink, CompressionMode.Decompress);
int c = test.Read(buffer, offset, count);
return c;
}
...
}
I can then specify the filter on the request object like this:
void Application_BeginRequest(object sender, EventArgs e)
{
string contentEncoding = Request.Headers["Content-Encoding"];
Stream prevCompressedStream = Request.Filter;
if(contentEncoding == null || contentEncoding.Length == 0)
return;
contentEncoding = contentEncoding.ToLower();
if(contentEncoding.Contains("gzip"))
{
Request.Filter = new DecompressStream(Request.Filter);
}
}
I say partial answer because even though I can now process the incoming request, the response is getting a "Content-Encoding: gzip" header even though the response is not encoded. I can verify in Fiddler that the content is not encoded.
If I do encode the response, the client for the webservice fails. It seems that even though it is sending "Accept-Encoding: gzip", it does not in fact accept gzip compressed response. I can verify in Fiddler that the response is compressed and Fiddler will decompress it successfully.
So, now I'm stuck trying to get a stray "Content-Encoding: gzip" header removed from the response. I've removed all references I can find to compression from the application, the web.config, and IIS.

How to server-side cache ASP.NET custom HttpHandler response

I've got a custom HttpHandler in my ASP.NET application, that basically builds and returns a javascript object. I have no experience with server-side caching, and my (possibly incompetent) google searches aren't returning anything basic enough to get me started.
Could anyone provide a very simple example to give me an idea of how to access and use the server-side cache from a custom HttpHandler, or, leave some links to get me started? Thanks a lot.
Additional info: I'm on IIS 6, and my code-behind is in C# (although a VB example would work as well).
Very simple example to get you started, without locking or error handling:
public void ProcessRequest(HttpContext context) {
MyObject thing = context.Cache["object_name"];
if (thing == null) {
thing = new MyObject();
context.Cache["object_name"] = thing;
}
// use thing here to process request
}

Security for Flex app when ssl is not available

So I know the best practice would be to run my Flex app over ssl along with implementing other forms of security however that isn't an option at this point (for monetary reasons and the app simply doesn't need that much security otherwise my sponsors would pay for it). However, I would like to implement some form of security and I'm wondering whether it's even worth it when I don't have ssl to protect the transactions.
So my setup is that I have a ASP.Net server side with a Flex UI. Right now the UI is the only thing that protects access to the sever: the server doesn't do any sort of verification during each request, it just assumes the person is allowed to do it. Obviously, anybody could write a program to generate posts (even if I could use SSL it would be like swiss cheese). Like I said before, security isn't a big deal, this is an internal app and it's nothing critical, however I do believe in doing things right. Would keeping the user info in session be a viable option and then verifying that the given user has permission, etc. Perhaps some sort of token system?
What would your preferred method of protecting this setup be?
...and no, I won't give you the url :)
ASP.NET Session itself is token based security and yes you can easily implement that by doing
[WebMethod(true)]
and yes, any web method requires login to be done first, it should call User.IsAuthenticated, that verifies the session token.
You can easily implement form authentication (let web.config empty, you can use FormsAuthentication in code).
for example,
[WebMethod(true)]
public string DoLogin(
string username,
string password)
{
//.. do your verification
FormsAuthentication.SetAuthCookie(username,false);
return "Login Sucessful";
}
[WebMethod(true)]
public string ChangePassword(
string oldPass,
string newPass)
{
// verify user is logged on or not..
if(!User.IsAuthenticated)
return "Please Login";
// The code below is secure, only
// authenticated user will go through below
// change pass...
return "Password Changed Successfully.";
}
We developed many Flex+ASP.NET sites, we did exactly same thing, but instead of return "string" we usually return a class like following...
public class WSResult<T>{
public bool Successful;
public string Message;
public T Result;
public T[] Results;
}
The convention is simple, if method was successful then you return Success = true, and depending upon whether you want to return an array of items or just single item, you can return either Results or Result. In case if there has been any error or unathorized access you can set Successful=false and set Message as detailed string. As per following example.
[WebMethod(true)]
public WSResult<BusinessUser> DoLogin(
string username,
string password)
{
try{
BusinessUser user = BusinessUser.GetByUsername(username);
if(user==null)
throw new Exception("User not found");
if(user.Password != password)
throw new Exception("Password did not match");
return new WSResult<BusinessUser>{ Result=user };
}catch(Exception ex)
{
// this will even catch any DAL exceptions or any system error as well
// Log Exception... somewhere for tracking...
return new WSResult<BusinessUser>{ Successful=false, Message = ex.Message };
}
}
Unfortunately, I know diddly squat about flex, but I think I can help anyway. I think you have two reasonably good options.
First though, we need to clarify something... Are you saying the server doesn't do any authorization? Does it at least have the ability to authenticate a user? Do you have any control over the server code? If not, I don't think the following suggestions will help. I'm not sure how you're supposed to secure a server with just client side code. Maybe there is a way, but I can't think of it.
1) Use HTTP digest authentication. This requires that the server is configured to understand it and that there is support in the flex api for adding the appropriate auth header to the HTTP request. The server authenticates the user by his password and can check what operations can be performed by said user against some authorization mechanism.
2) Follow the guidelines in this article to implement the authentication scheme that many atom publishing endpoints use. The flex api will have to provide some support for this, maybe there is an existing third party lib though. If you can get access to the HTTP headers you should be able to implement the rest.
Good luck.
How are you commuicating with the server SOAP. REST etc?
If it is SOAP have a look at the answer to this question
General Password Security && Implementation in Actionscript 3
and here's a link how to add the header to the SOAP message
How to add a "flat" message header to a flex web service call?
Hope this helps
Jon

Bypass Forms Authentication auto redirect to login, How to?

I'm writing an app using asp.net-mvc deploying to iis6. I'm using forms authentication. Usually when a user tries to access a resource without proper authorization I want them to be redirected to a login page. FormsAuth does this for me easy enough.
Problem: Now I have an action being accessed by a console app. Whats the quickest way to have this action respond w/ status 401 instead of redirecting the request to the login page?
I want the console app to be able to react to this 401 StatusCode instead of it being transparent. I'd also like to keep the default, redirect unauthorized requests to login page behavior.
Note: As a test I added this to my global.asax and it didn't bypass forms auth:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
HttpContext.Current.SkipAuthorization = true;
}
#Dale and Andy
I'm using the AuthorizeAttributeFilter provided in MVC preview 4. This is returning an HttpUnauthorizedResult. This result is correctly setting the statusCode to 401. The problem, as i understand it, is that asp.net is intercepting the response (since its taged as a 401) and redirecting to the login page instead of just letting it go through. I want to bypass this interception for certain urls.
Ok, I worked around this. I made a custom ActionResult (HttpForbiddenResult) and custom ActionFilter (NoFallBackAuthorize).
To avoid redirection, HttpForbiddenResult marks responses with status code 403. FormsAuthentication doesn't catch responses with this code so the login redirection is effectively skipped. The NoFallBackAuthorize filter checks to see if the user is authorized much like the, included, Authorize filter. It differs in that it returns HttpForbiddenResult when access is denied.
The HttpForbiddenResult is pretty trivial:
public class HttpForbiddenResult : ActionResult
{
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
context.HttpContext.Response.StatusCode = 0x193; // 403
}
}
It doesn't appear to be possible to skip the login page redirection in the FormsAuthenticationModule.
Might be a kludge (and may not even work) but on your Login page see if Request.QueryString["ReturnUrl"] != null and if so set Response.StatusCode = 401.
Bear in mind that you'll still need to get your console app to authenticate somehow. You don't get HTTP basic auth for free: you have to roll your own, but there are plenty of implementations about.
Did you write your own FormsAuth attribute for the action? If so, in the OnActionExecuting method, you get passed the FilterExecutingContext. You can use this to pass back the 401 code.
public class FormsAuth : ActionFilterAttribute
{
public override void OnActionExecuting(FilterExecutingContext filterContext)
{
filterContext.HttpContext.Response.StatusCode = 401;
filterContext.Cancel = true;
}
}
This should work. I am not sure if you wrote the FormsAuth attribute or if you got it from somewhere else.
I haven't used the AuthorizeAttribute that comes in Preview 4 yet. I rolled my own, because I have been using the MVC framework since the first CTP. I took a quick look at the attribute in reflector and it is doing what I mentioned above internally, except they use the hex equivalent of 401. I will need to look further up the call, to see where the exception is caught, because more than likely that is where they are doing the redirect. This is the functionality you will need to override. I am not sure if you can do it yet, but I will post back when I find it and give you a work around, unless Haacked sees this and posts it himself.
I did some googling and this is what I came up with:
HttpContext.Current.Response.StatusCode = 401;
Not sure if it works or not, I haven't tested it. Either way, it's worth a try, right? :)

Resources