|
Cross-site request forgery (xsrf)
Summary: |
This page describes a particular form of cross-site scripting
attack known as cross-site request forgery. It also
shows how such attacks can be prevented.
|
A cross-site request forgery (XSRF) is an action on a web application
by an unknowing but authenticated user,
who did not prepare nor may not be aware of the action.
It arises from the application's sometimes mistaken belief that form responses
are always part of a dialog: application sends form; user submits form.
The forgery works like this:
- An attacker learns the form inputs, names and values. Often by visiting the application themself.
- The attacker creates a page with the target's form, filled out with forged values*.*
- A user of the application authenticates and works at the target site.
- The user visits the attacker's page.
- The attacker's page, using active controls, causes the user's browser to submit the forged form to the target application.
- Because the user is authenticated at the application the transaction is valid.
Fortunately xsrf attacks are easy to frustrate.
If each form carries a secret token unique to the authenticated user and unguessable by the attacker,
the attacker can no longer provide all the inputs necessary for the action.
To be effective the token must:
- Be unique for each user.
- Be unguessable.
- Vary with instance.
A one-way hash function acting on a contenation of these elements generates such a token.
- userid
- an application secret text
- a timestamp
Each form sent to a user includes the timestamp and the token. On receipt of any form the application verifies that the token is in accord with the userid and timestamp.
This is some example code, written in c, that illustrates how
an XSRF attack can be thwarted. It is for illustartion only
and will not run without modification for your application.
Please note:
/* ========================================================================
* Copyright (c) 2006 The University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================================
*/
/* Using web security tokens to provent xsrf attacks. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <openssl/sha.h>
/* Generate a security token. Openssl's sha1 algorithm
provides an effective one-way hash.
Inputs the userid and a string timestamp.
Outputs the token as a string. */
char *xsec_gen_token(char *id, char *ts)
{
unsigned char hash[SHA_DIGEST_LENGTH];
char *tok = (char*) malloc(SHA_DIGEST_LENGTH*2 + 1);
unsigned char *txt;
char *secret = "Random secret, could be read from a file";
int txt_len;
int i,j;
/* Check that we have the necessary data. */
if (!(secret && id && ts)) return (NULL); /* Create the hash */
txt = (char*) malloc(strlen(secret)+strlen(id)+strlen(ts)+1);
strcat(strcat(strcpy(txt,secret),id),ts);
txt_len = strlen(txt);
SHA1(txt, txt_len, hash);
/* Convert the hash to characters. */
for (i=0,j=0;i<SHA_DIGEST_LENGTH;i++) {
unsigned int x;
tok[j++] = ((x=hash[i]%16)<10)?x+'0':x-10+'a';
tok[j++] = ((x=hash[i]/16)<10)?x+'0':x-10+'a';
}
tok[j] = '\0';
free (txt);
return (tok);
}
/* Verify a suspect token.
Returns true (1) if the input token jibes with the data. */
int xsec_chk_token(char *xtok, char *id, char *ts)
{
char *tok = xsec_gen_token(id, ts);;
if ((!tok) || strcmp(tok,xtok))) return (0);
return (1);
}
/* Example to set the security form fields.
This example write the text directly. A real application
would likely use a toolkit API to add elements to a form. */
void xsec_add_security_inputs()
{
time_t now = time(NULL);
char nowtxt[24];
char *id = getenv("REMOTE_USER"); /* userid from pubcookie, possibly */
char *tok;
/* generate the values */
sprintf(nowtxt,"%d",now);
tok = xsec_gen_token(id, nowtxt);
/* Add them to the form */
printf("<input type=\"hidden\" name=\"xtime\" value=\"%s\">\n", nowtxt);
printf("<input type=\"hidden\" name=\"xtoken\" value=\"%s\">\n", tok);
free(id);
free(tok);
}
/* Example to validate the security tokens from a form.
Form data is generally available through a toolkit.
This example assumes the external procedure "get_form_value"
provides that function.
Return true (1) if the token is valid. */
int xsec_chk_valid_form()
{
char *xtim = get_form_value("xtime");
char *xtok = get_form_value("xtoken");
time_t exp, now;
char *id = getenv("REMOTE_USER");
/* Make sure we have the inputs */
if (!(xtim && xtok && *xtim && *xtok && id && *id)) {
/* Deal with an invalid form. */
return (0);
}
/* Use the input timestamp (xtim) to detect
an expired form. This is an optional step.
Timeouts may be caught elsewhere in the application. */
exp = atoi(xtim) + FORM_TIMEOUT_SECONDS;
now = time(NULL);
if (now>exp) {
/* Deal with an expired form */
return (0);
}
/* Validate the securioty token. */
if (!xsec_chk_token(xtok, id, xtim)) {
/* Deal with an invalid security token */
return (0);
}
/* The security token is valid. */
return (1);
}
[an error occurred while processing this directive]
Jim Fox
UW Technology
Identity and Access Management
University of Washington
fox@washington.edu
[an error occurred while processing this directive]
|
|
[an error occurred while processing this directive]
|