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:
- 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.
- Insert the token is inserted into the HTTP request form as a hidden field.
- When the form is submitted, the token is compared to the one in the session. If it is not matched, proceed as an error.
- 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:
- Define an entity XSRF_CHECK with two fields SID and TOKEN. Set SID as the primary key.
- 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.
- 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"
- 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
- 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"