如何通过域而不是IP限制经典的ASP页面访问?

时间:2019-04-16 15:07:42

标签: asp-classic restriction

我希望编写一些代码来捕获用户的域名,并使用它来允许他们访问或不允许他们访问页面内容。

1 个答案:

答案 0 :(得分:0)

I am talking about the same thing as restricting access to a page via IP address but using the domain instead. I.E. yoursite.com ... I am trying to keep yoursite.com from having access to my form. This is an effort to restrict access from Russia domain that uses one domain but multiple ever-changing IP addresses.

It depends what you mean by "having access". If you're wanting to prevent a website from using/spamming a form that you host, then there's a few things you can do. Start by implementing CORS restrictions in your web.config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="X-Frame-Options" value="SAMEORIGIN" />
        <add name="Access-Control-Allow-Origin" value="https://yourdomain.com" />
      </customHeaders>
    </httpProtocol>
    </system.webServer>
</configuration>

Set Access-Control-Allow-Origin to your own domain. This will prevent JavaScript on another website from being able to make POST or GET request to your form.

Set X-Frame-Options to SAMEORIGIN

This will prevent other websites from being able to display your site in an iFrame.

You should also use CSRF tokens. A third party website accessing a form that you host isn't strictly a CSRF issue (actual CSRF exploits tend to use hidden iFrames on the attackers site, which are used to hijack an active session a visitor might have with another website. This is prevented by the other website requiring a token to be included with each form submission). But using CSRF tokens is still good practice and a good deterrent when trying to prevent other websites from having access to a public form that you host.

There are many ways to implement CSRF tokens (and there's lots of tutorials) But this is my preferred method which uses CSRF cookies, as demonstrated in this simple web form:

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<%  

    response.Charset = "utf-8"

    Const CSRF_token_max = 9999999999999
    Const CSRF_token_min = 1000000000000  

    sub create_CSRF_cookie(ignoreFormPost)

        ' Response.Cookies and Request.Cookies don't behave as you'd expect in Classic ASP.

        ' Response.Cookies is used to create a new cookie which is return in the HTTP 
        ' response headers, so the client can store it locally.

        ' Request.Cookies is used to retrieve a cookie from the HTTP request headers, which 
        ' are included in every HTTP request the client makes to the server.

        ' But here's the catch:

        ' If you use Response.Cookies to create a new cookie, but during the same page load 
        ' you also use Request.Cookies to retrieve the cookie you have just set, ASP will 
        ' return the value of the cookie waiting to be sent back to the client in the response 
        ' headers, despite the cookie having never left the server.

        ' This has it's uses, but if we issue a new CSRF cookie before processing a form post, 
        ' Request.Cookies("CSRF") will return the value of the new CSRF cookie rather than the 
        ' value of the cookie contained in the request headers, and thus a CSRF token mismatch 
        ' will occur.

        if request.form = "" OR ignoreFormPost then

            Dim CSRF_token

            Randomize()

            CSRF_token = Int((CSRF_token_max-CSRF_token_min+1)*Rnd+CSRF_token_min)

            ' Save the CSRF token as a cookie. 
            ' HttpOnly must be false, which is it by default in classic asp.

            Response.Cookies("CSRF") = CSRF_token

        end if

    end sub

    ' Create a new CSRF cookie on each page load
    ' Set "ignoreFormPost" to false. We don't want to create a new cookie if a form has been posted.
    ' We will do that once the form has been validated and processed.

    call create_CSRF_cookie(false)  

    '---------------------------------------------------------------
    ' Process a form POST
    '---------------------------------------------------------------

    if request.form("formName") = "CSRFform" then

        Dim hostName, responseStatus, responseColor, expectedCSRF, postedCSRF, postedText

        ' Is your domain using http or https?

        if Request.ServerVariables("HTTPS") = "on" then _
        hostName = "https://" else hostName = "http://"

        ' Build your hostname, e.g: http://yourdomain.com

        hostName = hostName & Request.ServerVariables("HTTP_HOST")        

        expectedCSRF = request.cookies("CSRF")
        postedCSRF = request.Form("CSRF")
        postedText = request.Form("text")

        ' Was the form submitted from your domain?  
        ' Is the CSRF token in the form data the correct length?
        ' Does the CSRF token in the form data match the CSRF token in the cookie?

        if inStr(1,Request.ServerVariables("HTTP_REFERER"),hostName,1) = 1 _    
        AND len(request.form("CSRF")) = len(CSRF_token_max) _ 
        AND request.Form("CSRF") = request.cookies("CSRF") then 

            ' Everything checks out. Do whatever it is you need to do

            responseColor = "#00CD42"
            responseStatus = "Form submitted successfully"

        else

            ' verification failed

            responseColor = "#E00025"
            responseStatus = "Form validation failed"

        end if

        ' Create a new CSRF cookie and tell the sub to ignore the fact that a form was posted.
        ' We've processed the form now so a new CSRF cookie can be issued.

        call create_CSRF_cookie(true)

    end if

%><!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<% 

    ' We could populate the hidden CSRF field with the "CSRF_token" variable.
    ' But instead, we're going to retrieve the token from the CSRF cookie
    ' as the form is submitted and insert it into the CSRF hidden field.

    ' Why get the CSRF token from the cookie? Well, let's assume you have 
    ' many forms that require a CSRF token. If the user loads a form and
    ' we populate the CSRF field with the "CSRF_token" variable, great...
    ' but what if they open another form before submitting this one. A new
    ' CSRF cookie will be generated. The form will be validated just fine,
    ' but if they go back to the previous form and submit it, the CSRF cookie
    ' will have changed and the form will fail to validate.

    ' This method allows us to generate a new CSRF cookie each time one is
    ' required, and forms that have already been generated but forgotten
    ' about will still be verified once the user gets round to submitting it.

    ' It's quite a common CSRF technique and one I borrowed/stole from Pythons
    ' Django framework. Ideally, forms should be posted and handled using ajax, 
    ' this would avoid validation fails when resubmitting a form on a page reload

%>
<form method="post" name="CSRFform" onsubmit="getCSRF()">
    <table width="<%  if request.form("formName") = "CSRFform" then response.write "5" %>0%" border="1" cellspacing="2" cellpadding="6">
      <tbody>
        <tr>
          <td>
            <input type="text" name="text" value="<%=Server.HTMLEncode(request.form("text"))%>" placeholder="Enter some text">
            <input type="hidden" id="CSRF" name="CSRF" value="">
            <input type="hidden" name="formName" value="CSRFform">
            <input type="submit" value="Submit">
          </td>
        </tr>
        <%  if request.form("formName") = "CSRFform" then %>
        <tr>
          <td bgcolor="<%=responseColor%>" style="color:#ffffff; font-size:18px; font-weight:bold;"><%=responseStatus%></td>
        </tr>
        <tr>
          <td>
          <%

            if postedCSRF = "undefined" then postedCSRF = "NA"
            if expectedCSRF = "" then expectedCSRF = "NA"
            if postedText = "" then postedText = "NA"

            response.write "<p><b>Referer</b>: " & Request.ServerVariables("HTTP_REFERER") & "</p>"
            response.write "<p><b>Expected Referer</b>: " & hostName & "/*</p><hr>"
            response.write "<p><b>CSRF Token</b>: " & postedCSRF & "</p>"
            response.write "<p><b>Expected CSRF Token</b>: " & expectedCSRF & "</p><hr>"
            response.write "<p><b>CSRF Length</b>: " & len(replace(postedCSRF,"NA","")) & "</p>"
            response.write "<p><b>Expected CSRF Length</b>: " & len(CSRF_token_max) & "</p><hr>"
            response.write "<p><b>Posted Text</b>: " & Server.HTMLEncode(postedText) & "</p>"

           %> 
          </td>
        </tr>
        <% end if %>
      </tbody>
    </table>
</form>

<script>

    // Get the most recent CSRF token from the cookies 

    function getCSRF() {
        document.getElementById("CSRF").value = getCookie("CSRF");  
    }

    function getCookie(name) {
        var value = "; " + document.cookie;
        var parts = value.split("; " + name + "=");
        if (parts.length == 2) return parts.pop().split(";").shift();
    }

</script>

<body>
</body>
</html>

You'll notice that as well as validating the CSRF token, I'm also checking the HTTP_REFERER against the servers domain name. Whenever a form is submitted the HTTP_REFERER header contains the URL of the website that submitted the post (this is issued by the browser and cannot be spoofed using a standard HTTP POST request). If the form wasn't submitted from your domain, then the form data won't be processed.

So at this point, it's now impossible for a third party website to use client side code to spam or manipulate a form that you host. This is because we're:

  1. Requiring a valid token to be returned with each post request, and the token can only be issued and accessed on your website.

  2. Checking the HTTP_REFERER header to make sure the post request was made from your website.

  3. Using Access-Control-Allow-Origin to prevent javascript/ajax from posting to your form from a thrid party websites (javascript/ajax could potentially be used to spoof a fake HTTP_REFERER header)

However... if an attacker chooses to access your form using server-side code, then this opens up a whole can or worms. Browsers are required to abide by very strict rules, but when you take browsers out of the equation and use server-side code to access and manipulate a web form on another website, those rules can be bypassed. It would be possible for an attacker to use cURL (or a similar protocol) to request your web form, read the CSRF cookie issued by your server in the response headers, use that CSRF token to validate the form, post the form back to your server along with the CSRF cookie you issued AND spoof the HTTP_REFERER header making it appear as the form was submitted from your website. The attacker would have essentially created a bot, and these are very difficult to detect and prevent against, especially since they can spoof other headers too, such as the HTTP_USER_AGENT.

There are solutions to this though which use algorithms to detect suspicious activity. CloudFlare offers a really good bot management services that is great for detecting and blocking bots as well as general data scraping/mining: https://www.cloudflare.com/lp/bot-management/