Is Request.IsLocal secure or can it be spoofed?

2019-01-24 12:54发布

问题:

I have a webpage which checks for an encrypted cookie on page load to determine user identity. However, when I'm testing the page locally on my development box, I don't have access to that cookie.

Previously I used an appsetting to tell the page whether it was in development mode or not, and when in dev-mode it would load a fixed user identity. Then I discovered Request.IsLocal

I can simply check like this:

if(Request.IsLocal){
   FormsAuthentication.SetAuthCookie("testUser", false);
}else{
   FormsAuthentication.SetAuthCookie(/*EncryptedCookieValue*/, false);
}

Is this secure? Is there any way a malicious user could spoof IsLocal?

回答1:

I think your actual question is, how do you have development only functionality?

You could you use: Environment.UserInteractive
http://msdn.microsoft.com/en-us/library/system.environment.userinteractive.aspx

It returns false when running in IIS or a Windows Service, true when their is a user interface i.e. Visual Studio when your developing.

I think this is better than a DEBUG pre processor variable because the behaviour is more consistent, you could accidentally upload a DEBUG version of your dll to your live environment unless you have a very tight build/release process.

As a rule of thumb it's not a good idea to trust anything from the client.
I'd also be pragmatic, what are you protecting and how much effort would someone go to hack in?

The below SO post goes into some of the reasons why you shouldn't trust it:
Can I fool HttpRequest.Current.Request.IsLocal?

Reference
You can view the source at http://referencesource.microsoft.com

public bool IsLocal { 
   get {
      String remoteAddress = UserHostAddress; 

      // if unknown, assume not local
      if (String.IsNullOrEmpty(remoteAddress))
         return false; 

      // check if localhost 
      if (remoteAddress == "127.0.0.1" || remoteAddress == "::1") 
         return true;

      // compare with local address
      if (remoteAddress == LocalAddress)
         return true;

      return false;
   } 


回答2:

The code for IsLocal appears to be robust - I can't see any flaws in its logic so for your purposes it should be fine.

However, you should be aware that if your application (or any other application running on the same server) makes any HTTP requests whose destination can be influenced by the end user then you should add an extra layer of security such as a secret/expiring key or token to your request or you could secure the HTTP request when made so that it is not possible to request a local resource.

e.g. Say your website has an end point such as http://www.example.com/DeleteAllUsers and in the code that handles this request you are checking IsLocal to make sure that users can only be deleted if it is a local, trusted request.

Now let's say you have a function on your website Enter a web address to view headers: and the user enters http://www.example.com/DeleteAllUsers in this text box, causing your application to request DeleteAllUsers and satisfy the IsLocal security check because the HTTP request is made from your app. This is how IsLocal can be exploited, and I realise it is a contrived example to prove the point, but lots of websites do similar things such as grabbing a preview image of a URL to display. If nothing on your server can be made to make a local HTTP request you should be good to go.



回答3:

You should not put this code on a production server, for the reasons mentioned in the other answers.

However, you could do

#if DEBUG
    if (Request.IsLocal)
    {
        FormsAuthentication.SetAuthCookie("testUser", false);
    }
    else
    {
#endif
        FormsAuthentication.SetAuthCookie(/*EncryptedCookieValue*/, false);
#if DEBUG
    }
#endif

On your development box, run a Debug build. In production, deploy a Release build.



回答4:

Determining the remote IP is tricky and depends on configuring the server correctly.

For example a misconfigured server might use X-Forwarded-For to determine the IP, but it can be chosen by the client. But when using a reverse proxy that sets it to its own IP, this is the correct way to determine the IP.

Using the IP from the socket can be wrong as well, consider a reverse proxy running on the machine as the webserver.

=> If possible use a different authentication mechanism