Cross-Site Request Forgery

Cross-site request forgery (also known as CSRF or XSRF), is a type of the web site attack in which a malicious script or URL sends an HTTP request to an external site for which the user is currently authenticated.

Any functionality on the web can be a target of XSRF. It could be authentication process, posting text to blog, searching an internal document, performing a banking transaction, sending an email, and so on.

For example, a web shop (shop.com) requires users to log in before placing an order by the HTTP request (http://shop.com/order.html?productid=<id>). The user is already logged in and visits a site that contains a malicious image tag <img src="http://shop.com/order.html?productid=abc">. The link is loaded in the user's browser, thereby initiating an order that was not intended.

POST Method Attacks

Another example uses the POST method. An attacker prepares a web page attack.html:

<html>
<body onLoad="document.attack.submit();">
<form name="attack" method="post" action="http://shop.com/order.html">
  <input type="hidden" name="productid" value="abc">
  <input type="submit" value="send”>
</form>
</body>
</html>

And creates a welcome page (welcome.html):

<html>
<body>
Welcome!!
<iframe width="1" height="1" src="attack.html"></iframe>
</body>
</html>

When the user accesses the Welcome page, the attack.html page is automatically loaded in the inline frame and http://shop.com/order.html is called with POST parameters by the onLoad attribute of body element, without the user noticing.

Defenses

It is not possible to protect against cross-site forgery attacks from the client side. To prevent cross-site request forgery attacks, you need to add a unique token to each request, and verify it upon submission:

  1. Generate a token and store it on the server associated with the user’s session. The token must be random and long enough to be resistant to brute-force cracking.
  2. Insert the token is inserted into the HTTP request form as a hidden field.
  3. When the form is submitted, the token is compared to the one in the session. If it is not matched, proceed as an error.
  4. Discard the token and generate another for each session or request. A new token for each request is more secure but results in the user not being able to use the browser's Back button. A new token per request cannot be used for an asynchronous request, so here the default should be a token per session.

Using and Validating Session Tokens

The following example demonstrates how you can achieve this in a Uniface application:

  1. Define an entity XSRF_CHECK with two fields SID and TOKEN. Set SID as the primary key.
  2. Add the XSRF_CHECK entity to the component structure of s DSP and load all fields. You don’t need to put the fields into the layout.
  3. In exec operation, create a token using $uuid, and store it with the session ID, which can be obtained by $webinfo ("WEBSERVERCONTEXT").
    ; get the session ID
    WebServerContext = $webinfo("WEBSERVERCONTEXT")
    getitem/id SessionID, WebServerContext, "SESSION"
    
    ; store Session ID and Token in DB
    SID.XSRF_CHECK = SessionID
    TOKEN.XSRF_CHECK = $uuid
    store/e "XSRF_CHECK"
  4. To process a request, in the preRequest trigger, check the value of TOKEN field and compare it with the one in the database. If it is not matched, proceed as an error.
    ; get the token in the request
    req_token = TOKEN.XSRF_CHECK
    
    ; get the session ID
    WebServerContext = $webinfo("WEBSERVERCONTEXT")
    getitem/id SessionID, WebServerContext, "SESSION"
    
    ; retrieve the token in DB with the session ID
    SID.XSRF_CHECK = SessionID
    retrieve/e "XSRF_CHECK"
    
    ; compare those tokens
    if (req_token <> TOKEN.XSRF_CHECK)
        ; prevent the XSRF attack
        return –1
    endif
    
    ; proceed further
  5. To discard the token per request, create the new token and replace it in the database.
    ; store new token in DB
    TOKEN.XSRF_CHECK = $uuid
    store/e "XSRF_CHECK"

Related Topics