How to prevent direct access to pages through the URL address bar

How to prevent direct access to pages through the URL address bar

1. Solutions

1. Put all pages in the WEB-INF directory

  WEB-INF is a Java web application security directory, which is only open to the server and invisible to the client. Therefore, we can put all pages except the home page (index.jsp) in the WEB-INF directory, so that the pages cannot be accessed directly through the URL.

2. The referer value in the http request header field

  According to the HTTP protocol, there is a field in the HTTP header called Referer, which records the source address of the HTTP request. In general, requests to access a security-restricted page must come from the same website. For example, the transfer of a bank is completed by the user visiting the http://bank.test/test?page=10&userID=101&money=10000 page. The user must first log in to bank.test, and then click the button on the page to trigger the transfer event. When the user submits the request, the Referer value of the transfer request will be the URL of the page where the transfer button is located (in this case, usually the address starting with the domain name of bank.test). If an attacker wants to carry out a CSRF attack on a bank's website, he can only construct a request on his own website. When a user sends a request to the bank through the attacker's website, the Referer of the request points to the attacker's website. Therefore, to defend against CSRF attacks, the bank website only needs to verify its Referer value for each transfer request. If the domain name starts with bank.test, it means that the request is from the bank website itself and is legal. If the Referer is another website, it may be a CSRF attack, and the request will be rejected.

3. Add the token to the request address and verify

  The reason why the CSRF attack is successful is that the attacker can forge the user's request, and all the user authentication information in the request exists in the cookie, so the attacker can directly use the user's own cookie without knowing the authentication information. to pass security verification. It can be seen from this that the key to resisting CSRF attacks is to put information that cannot be forged by the attacker in the request, and the information does not exist in the cookie. In view of this, system developers can add a randomly generated token in the form of a parameter to the HTTP request, and establish an interceptor on the server side to verify the token. If there is no token in the request or the token content is incorrect, it may be CSRF attack and reject the request.

4. Customize attributes in HTTP headers and verify

  The method of customizing attributes is also to use tokens and verify them. The difference from the previous method is that the token is not placed in the HTTP request as a parameter, but is placed in a custom attribute in the HTTP header. inside. Through the XMLHttpRequest class, you can add the csrftoken HTTP header attribute to all requests of this type at one time, and put the token value into it. This solves the inconvenience of adding a token to the request in the previous method. At the same time, the address requested through this class will not be recorded in the browser's address bar, and there is no need to worry that the token will be leaked to other websites through Referer.

5. Other defense methods

(1) CSRF attacks are conditional. When a user accesses a malicious link, the authentication cookie is still valid, so when the user closes the page, it is necessary to clear the authentication cookie in time, which is particularly important for browsers that support TAB mode (opening a web page in a new tab). .

(2) Minimize or do not use the request() class variable as much as possible, and specify request.form() or request.querystring() as a parameter to prevent CSRF vulnerability attacks. This method cannot completely defend against CSRF attacks, but only to a certain extent. increase the difficulty of the attack.

2. Java code example

No matter which method is used, the interceptor on the server side is essential, it will be responsible for checking whether the incoming request meets the requirements, and then decide whether to continue the request or discard it depending on the result. In Java, interceptors are implemented by Filters. We can write a Filter and configure it in web.xml to intercept requests to access all resources that require CSRF protection.

The referer verification code for the request in the filter is as follows:

/** 1. Verify Referer in Filter */

 // Get the Referer value from the HTTP header 
 String referer=request.getHeader("Referer" );
  // Determine whether the Referer starts with bank.example 
 if ((referer!= null ) && (referer.trim().startsWith(" bank.example”))){
    chain.doFilter(request, response);
 }else{
  request.getRequestDispatcher(“error.jsp”).forward(request,response);
 }

The above code first obtains the Referer value, and then judges it. When it is not empty and starts with bank.example, the request will continue. Otherwise, it may be a CSRF attack and go to the error.jsp page.

If you want to further verify the token value in the request, the code is as follows:

/** 2. Verify the token in the request in the filter */

HttpServletRequest req = (HttpServletRequest)request;
HttpSession s = req.getSession();
 // Get the csrftoken attribute from the session 
String sToken = (String)s.getAttribute("csrftoken");
 if (sToken == null ){
     // Generate a new token and put it into the session 
    sToken = generateToken();
    s.setAttribute("csrftoken",sToken);
    chain.doFilter(request, response);
} else {
     // Get csrftoken from HTTP header 
    String xhrToken = req.getHeader("csrftoken");
     // Get csrftoken from request parameter 
    String pToken = req.getParameter("csrftoken");
     if (sToken != null && xhrToken != null &&          sToken.equals(xhrToken)){
        chain.doFilter(request, response);
    }else if(sToken != null && pToken != null && sToken.equals(pToken)){
        chain.doFilter(request, response);
}else{
    request.getRequestDispatcher(“error.jsp”).forward(request,response);
    }
}     

First, judge whether there is csrftoken in the session. If not, it is considered to be the first visit, and the session is newly established. At this time, a new token is generated, placed in the session, and the request is continued. If there is already a csrftoken in the session, it means that the user has established an active session with the server. At this time, it depends on whether this token is attached to the request. Since the request may come from conventional access or XMLHttpRequest asynchronous access, We try to obtain the csrftoken parameter from the request and the csrftoken custom attribute from the HTTP header and compare it with the value in the session. As long as there is a valid token in one place, it is determined that the request is legal and can continue to execute, otherwise go to error page. There are many ways to generate tokens, any random algorithm can be used, Java's UUID class is also a good choice.

In addition to using filter to verify the value of the token on the server side, we also need to attach this token to each request on the client side. This is to use js to attach the csrftoken code to the link and form request address in html, where the token has been defined For the global variable, its value can be obtained from the session.

/** 3. Attach a token to the request on the client side */

function appendToken(){
    updateForms();
    updateTags();
}

function updateForms() {
    // Get all form elements in the page 
    var forms = document.getElementsByTagName('form' );
      for (i=0; i<forms.length; i++ ) {
        var url = forms[i].action;
         // If the action value of this form is empty, the csrftoken will not be attached 
        if (url == null || url == "" ) continue ;
         // Dynamically generate the input element and add it to after form 
        var e = document.createElement("input" );
        e.name = "csrftoken";
        e.value = token;
        e.type="hidden";
        forms[i].appendChild(e);
    }
}

function updateTags() {
    var all = document.getElementsByTagName('a');
    var len = all.length;
     // traverse all a elements 
    for (var i=0; i<len; i++ ) {
        var e = all [i];
        updateTag(e, 'href', token);
    }
}

function updateTag(element, attr, token) {
    var location = element.getAttribute(attr);
    if(location != null && location != '' '' ) {
        var fragmentIndex = location.indexOf('#');
        var fragment = null ;
         if (fragmentIndex != -1 ){
             // url contains an anchor tag that only corresponds to the page 
            fragment = location.substring(fragmentIndex);
            location = location.substring(0,fragmentIndex);
        }
        var index = location.indexOf('?' );
         if (index != -1 ) {
             // url already contains other parameters 
            location = location + '&csrftoken=' + token;
        } else {
             // no other parameters in url 
        location = location + '?csrftoken=' + token;
        }
        if(fragment != null){
            location += fragment;
        }
        element.setAttribute(attr, location);
    }
}     

In the client html, there are mainly two places where the token needs to be added, one is the form form, and the other is the link a. This code first traverses all the forms, adds a hidden field at the end of the form, and puts the csrftoken in it. Then, the code iterates over all link tags a, adding the csrftoken parameter to their href attribute. Note that for a.href, the property may already have parameters, or an anchor tag. Therefore, it needs to be discussed on a case-by-case basis, and csrftoken is added to it in different formats.

If your website uses XMLHttpRequest, you also need to customize the csrftoken attribute in the HTTP header. Use dojo.xhr to add custom attributes to XMLHttpRequest. The code is as follows:

/** 4. Custom properties in HTTP headers */

var plainXhr = dojo.xhr;
 // Rewrite the dojo.xhr method 
dojo.xhr = function(method,args,hasBody) {
 // Make sure the header object exists 
args.headers = args.header || {};
tokenValue = '<%=request.getSession(false).getAttribute("csrftoken")%>';
var token = dojo.getObject("tokenValue" );
 // put the csrftoken attribute in the header 
args.headers["csrftoken"] = (token) ? token : " " ;
 return plainXhr(method,args,hasBody);
};

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324868101&siteId=291194637