Created
December 31, 2013 14:54
-
-
Save bennadel/8197963 to your computer and use it in GitHub Desktop.
Preventing Cross-Site Request Forgery (CSRF / XSRF) With AngularJS And ColdFusion
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<cfscript> | |
// Set up the default API response. | |
apiResponse = { | |
"statusCode" = 200, | |
"statusText" = "OK", | |
"contentType" = "application/x-json", | |
"data" = {} | |
}; | |
// When processing the API request, we are going to check to see | |
// if the XSRF cookie and header values match. If either of these | |
// values is missing, or they do not match, we'll raise an | |
// exception. This error-oriented routing simplifies the logic. | |
try { | |
// The value WE set. | |
xsrfCookie = cookie[ "XSRF-TOKEN" ]; | |
// The value ANGULARJS set. | |
xsrfToken = getHttpRequestData().headers[ "X-XSRF-TOKEN" ]; | |
if ( xsrfCookie != xsrfToken ) { | |
throw( type = "XsrfTokenMismatch" ); | |
} | |
apiResponse.data[ "method" ] = cgi.request_method; | |
apiResponse.data[ "time" ] = getTickCount(); | |
} catch ( any error ) { | |
// If we made it this far, some part of the XSRF validation | |
// failed. Either one of the tokens was missing; or, the two | |
// tokens did not match. In any case, the request is not valid. | |
apiResponse.statusCode = 401; | |
apiResponse.statusText = "Unauthorized"; | |
apiResponse.data = {}; | |
} | |
</cfscript> | |
<cfheader | |
statuscode="#apiResponse.statusCode#" | |
statustext="#apiResponse.statusText#" | |
/> | |
<!--- Serialize the API response. ---> | |
<cfcontent | |
type="#apiResponse.contentType#; charset=utf-8" | |
variable="#charsetDecode( serializeJson( apiResponse.data ), 'utf-8' )#" | |
/> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<cfscript> | |
// Set the XSRF token cookie. The cookie is user-specific and | |
// "salted". Once in place, AngularJS will look for this cookie | |
// before initiating the $http / $resource requests; when found, | |
// AngularJS will automatically echo the token in the HEADER | |
// value, "X-XSRF-TOKEN". | |
cookie[ "XSRF-TOKEN" ] = lcase( | |
hash( "#session.cfid#-#session.cftoken#-#getTickCount()#" ) | |
); | |
</cfscript> | |
<!--- ----------------------------------------------------- ---> | |
<!--- ----------------------------------------------------- ---> | |
<cfcontent type="text/html; charset=utf-8" /> | |
<!doctype html> | |
<html ng-app="demo"> | |
<head> | |
<meta charset="utf-8" /> | |
<title> | |
Preventing Cross-Site Request Forgery With AngularJS And ColdFusion | |
</title> | |
<style type="text/css"> | |
a[ ng-click ] { | |
color: blue ; | |
cursor: pointer ; | |
text-decoration: underline ; | |
} | |
</style> | |
</head> | |
<body ng-controller="DemoController"> | |
<h1> | |
Preventing Cross-Site Request Forgery With AngularJS And ColdFusion | |
</h1> | |
<p> | |
<a ng-click="makeGetRequest()">Make GET Request</a> | |
— | |
<a ng-click="makePostRequest()">Make POST Request</a> | |
— | |
<a href="delete_cookie.cfm" target="_blank">Delete XSRF Cookie</a> | |
</p> | |
<h3> | |
API Log | |
</h3> | |
<ul> | |
<li ng-repeat="item in apiLog"> | |
{{ item.message }} | |
</li> | |
</ul> | |
<script type="text/javascript" src="./assets/angularjs/angular.min.js"></script> | |
<script type="text/javascript" src="./assets/angularjs/angular-resource.min.js"></script> | |
<script type="text/javascript"> | |
// Define our AngularJS application. | |
var app = angular.module( "demo", [ "ngResource" ] ); | |
// -------------------------------------------------- // | |
// -------------------------------------------------- // | |
// I am the application controller. | |
app.controller( | |
"DemoController", | |
function( $scope, $resource ) { | |
// I keep track of the API request values. | |
$scope.apiLog = []; | |
// I create a proxy for the server-side API end-point. | |
// I sit on top of the $http resource and will append | |
// an "X-XSRF-TOKEN" header to all outgoing requests | |
// if the "XSRF-TOKEN" cookie value is available. | |
var resource = $resource( | |
"api.cfm", | |
{}, | |
{ | |
performGet: { | |
method: "GET" | |
}, | |
performPost: { | |
method: "POST" | |
} | |
} | |
); | |
// --- | |
// PUBLIC METHODS. | |
// --- | |
// I make GET requests to the API. | |
$scope.makeGetRequest = function() { | |
resource.performGet() | |
.$promise | |
.then( handleResolution, handleRejection ) | |
; | |
}; | |
// I make POST requests to the API. | |
$scope.makePostRequest = function() { | |
resource.performPost() | |
.$promise | |
.then( handleResolution, handleRejection ) | |
; | |
}; | |
// --- | |
// PRIVATE METHODS. | |
// --- | |
// I handle successful resource resolutions. | |
function handleResolution( response ) { | |
$scope.apiLog.unshift({ | |
message: ( response.method + ": " + response.time ) | |
}); | |
} | |
// I handle resource response rejections. | |
function handleRejection( response ) { | |
$scope.apiLog.unshift({ | |
message: "*** XSRF Attack! ***" | |
}); | |
} | |
} | |
); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment