/// <summary> /// Perform any initialisation tasks /// </summary> /// <param name="pipelines">Application pipelines</param> public void Initialize(IPipelines pipelines) { pipelines.AfterRequest.AddItemToEndOfPipeline( context => { if (context.Response == null || context.Response.Cookies == null) { return; } if (context.Items.ContainsKey(CsrfToken.DEFAULT_CSRF_KEY)) { context.Response.Cookies.Add(new NancyCookie(CsrfToken.DEFAULT_CSRF_KEY, (string)context.Items[CsrfToken.DEFAULT_CSRF_KEY], true)); return; } if (context.Request.Cookies.ContainsKey(CsrfToken.DEFAULT_CSRF_KEY)) { context.Items[CsrfToken.DEFAULT_CSRF_KEY] = HttpUtility.UrlDecode(context.Request.Cookies[CsrfToken.DEFAULT_CSRF_KEY]); return; } var token = new CsrfToken { CreatedDate = DateTime.Now, }; token.CreateRandomBytes(); token.CreateHmac(CryptographyConfiguration.HmacProvider); var tokenString = ObjectSerializer.Serialize(token); context.Items[CsrfToken.DEFAULT_CSRF_KEY] = tokenString; context.Response.Cookies.Add(new NancyCookie(CsrfToken.DEFAULT_CSRF_KEY, tokenString, true)); }); }
public void Should_return_token_mismatch_if_random_bytes_empty() { DateTime date = DateTime.Now; var tokenOne = new CsrfToken { CreatedDate = date, RandomBytes = ArrayCache.Empty<byte>() }; var tokenTwo = new CsrfToken { CreatedDate = date, RandomBytes = ArrayCache.Empty<byte>() }; tokenOne.CreateHmac(this.hmacProvider); tokenTwo.CreateHmac(this.hmacProvider); var result = this.validator.Validate(tokenOne, tokenTwo); result.ShouldEqual(CsrfTokenValidationResult.TokenTamperedWith); }
public void Should_return_token_ok_if_tokens_match_and_no_expiry_set() { DateTime date = DateTime.Now; var tokenOne = new CsrfToken { CreatedDate = date, RandomBytes = new byte[] { 1, 2, 3 } }; var tokenTwo = new CsrfToken { CreatedDate = date, RandomBytes = new byte[] { 1, 2, 3 } }; tokenOne.CreateHmac(this.hmacProvider); tokenTwo.CreateHmac(this.hmacProvider); var result = this.validator.Validate(tokenOne, tokenTwo); result.ShouldEqual(CsrfTokenValidationResult.Ok); }
public void Should_return_token_mismatch_if_tokens_differ() { DateTime date = DateTime.Now; var tokenOne = new CsrfToken { CreatedDate = date, RandomBytes = new byte[] { 1, 2, 3 } }; var tokenTwo = new CsrfToken { CreatedDate = date, RandomBytes = new byte[] { 1, 4, 3 } }; tokenOne.CreateHmac(this.hmacProvider); tokenTwo.CreateHmac(this.hmacProvider); var result = this.validator.Validate(tokenOne, tokenTwo); result.ShouldEqual(CsrfTokenValidationResult.TokenMismatch); }
/// <summary> /// Creates a new csrf token for this response with an optional salt. /// Only necessary if a particular route requires a new token for each request. /// </summary> /// <param name="module">Nancy module</param> /// <returns></returns> public static void CreateNewCsrfToken(this INancyModule module) { var token = new CsrfToken { CreatedDate = DateTime.Now, }; token.CreateRandomBytes(); token.CreateHmac(CsrfApplicationStartup.CryptographyConfiguration.HmacProvider); var tokenString = CsrfApplicationStartup.ObjectSerializer.Serialize(token); module.Context.Items[CsrfToken.DEFAULT_CSRF_KEY] = tokenString; }
/// <summary> /// Creates a new csrf token with an optional salt. /// Does not store the token in context. /// </summary> /// <returns>The generated token</returns> internal static string GenerateTokenString(CryptographyConfiguration cryptographyConfiguration = null) { cryptographyConfiguration = cryptographyConfiguration ?? CsrfApplicationStartup.CryptographyConfiguration; var token = new CsrfToken { CreatedDate = DateTime.Now, }; token.CreateRandomBytes(); token.CreateHmac(cryptographyConfiguration.HmacProvider); var tokenString = CsrfApplicationStartup.ObjectSerializer.Serialize(token); return(tokenString); }
/// <summary> /// Creates a new csrf token for this response with an optional salt. /// Only necessary if a particular route requires a new token for each request. /// </summary> /// <param name="module">Nancy module</param> /// <returns></returns> public static void CreateNewCsrfToken(this NancyModule module) { var token = new CsrfToken { CreatedDate = DateTime.Now, }; token.CreateRandomBytes(); token.CreateHmac(CsrfApplicationStartup.CryptographyConfiguration.HmacProvider); var tokenString = CsrfApplicationStartup.ObjectSerializer.Serialize(token); module.Context.Items[CsrfToken.DEFAULT_CSRF_KEY] = tokenString; }
public void Should_return_token_tampered_with_if_hmac_incorrect() { DateTime date = DateTime.Now; var tokenOne = new CsrfToken { CreatedDate = date, RandomBytes = new byte[] { 1, 2, 3 } }; var tokenTwo = new CsrfToken { CreatedDate = date, RandomBytes = new byte[] { 1, 2, 3 } }; tokenOne.CreateHmac(this.hmacProvider); tokenTwo.CreateHmac(this.hmacProvider); tokenOne.Hmac[0] -= 1; tokenTwo.Hmac[0] -= 1; var result = this.validator.Validate(tokenOne, tokenTwo); result.ShouldEqual(CsrfTokenValidationResult.TokenTamperedWith); }
/// <summary> /// Enables Csrf token generation. /// This is disabled by default. /// </summary> /// <param name="pipelines">Application pipelines</param> public static void Enable(IPipelines pipelines, CryptographyConfiguration cryptographyConfiguration = null) { cryptographyConfiguration = cryptographyConfiguration ?? CsrfApplicationStartup.CryptographyConfiguration; var postHook = new PipelineItem<Action<NancyContext>>( CsrfHookName, context => { if (context.Response == null || context.Response.Cookies == null || context.Request.Method.Equals("OPTIONS", StringComparison.OrdinalIgnoreCase)) { return; } if (context.Items.ContainsKey(CsrfToken.DEFAULT_CSRF_KEY)) { context.Response.Cookies.Add(new NancyCookie(CsrfToken.DEFAULT_CSRF_KEY, (string)context.Items[CsrfToken.DEFAULT_CSRF_KEY], true)); return; } if (context.Request.Cookies.ContainsKey(CsrfToken.DEFAULT_CSRF_KEY)) { var decodedValue = HttpUtility.UrlDecode(context.Request.Cookies[CsrfToken.DEFAULT_CSRF_KEY]); var cookieToken = CsrfApplicationStartup.ObjectSerializer.Deserialize(decodedValue) as CsrfToken; if (CsrfApplicationStartup.TokenValidator.CookieTokenStillValid(cookieToken)) { context.Items[CsrfToken.DEFAULT_CSRF_KEY] = decodedValue; return; } } var token = new CsrfToken { CreatedDate = DateTime.Now, }; token.CreateRandomBytes(); token.CreateHmac(cryptographyConfiguration.HmacProvider); var tokenString = CsrfApplicationStartup.ObjectSerializer.Serialize(token); context.Items[CsrfToken.DEFAULT_CSRF_KEY] = tokenString; context.Response.Cookies.Add(new NancyCookie(CsrfToken.DEFAULT_CSRF_KEY, tokenString, true)); }); pipelines.AfterRequest.AddItemToEndOfPipeline(postHook); }
/// <summary> /// Enables Csrf token generation. /// This is disabled by default. /// </summary> /// <param name="pipelines">Application pipelines</param> public static void Enable(IPipelines pipelines, CryptographyConfiguration cryptographyConfiguration = null) { cryptographyConfiguration = cryptographyConfiguration ?? CsrfApplicationStartup.CryptographyConfiguration; var postHook = new PipelineItem <Action <NancyContext> >( CsrfHookName, context => { if (context.Response == null || context.Response.Cookies == null || context.Request.Method.Equals("OPTIONS", StringComparison.OrdinalIgnoreCase)) { return; } if (context.Items.ContainsKey(CsrfToken.DEFAULT_CSRF_KEY)) { context.Response.Cookies.Add(new NancyCookie(CsrfToken.DEFAULT_CSRF_KEY, (string)context.Items[CsrfToken.DEFAULT_CSRF_KEY], true)); return; } if (context.Request.Cookies.ContainsKey(CsrfToken.DEFAULT_CSRF_KEY)) { var decodedValue = HttpUtility.UrlDecode(context.Request.Cookies[CsrfToken.DEFAULT_CSRF_KEY]); var cookieToken = CsrfApplicationStartup.ObjectSerializer.Deserialize(decodedValue) as CsrfToken; if (CsrfApplicationStartup.TokenValidator.CookieTokenStillValid(cookieToken)) { context.Items[CsrfToken.DEFAULT_CSRF_KEY] = decodedValue; return; } } var token = new CsrfToken { CreatedDate = DateTime.Now, }; token.CreateRandomBytes(); token.CreateHmac(cryptographyConfiguration.HmacProvider); var tokenString = CsrfApplicationStartup.ObjectSerializer.Serialize(token); context.Items[CsrfToken.DEFAULT_CSRF_KEY] = tokenString; context.Response.Cookies.Add(new NancyCookie(CsrfToken.DEFAULT_CSRF_KEY, tokenString, true)); }); pipelines.AfterRequest.AddItemToEndOfPipeline(postHook); }
/// <summary> /// Validates a pair of tokens /// </summary> /// <param name="tokenOne">First token (usually from either a form post or querystring)</param> /// <param name="tokenTwo">Second token (usually from a cookie)</param> /// <param name="validityPeriod">Optional period that the tokens are valid for</param> /// <returns>Token validation result</returns> public CsrfTokenValidationResult Validate(CsrfToken tokenOne, CsrfToken tokenTwo, TimeSpan?validityPeriod = new TimeSpan?()) { if (tokenOne == null || tokenTwo == null) { return(CsrfTokenValidationResult.TokenMissing); } if (!tokenOne.Equals(tokenTwo)) { return(CsrfTokenValidationResult.TokenMismatch); } if (tokenOne.RandomBytes == null || tokenOne.RandomBytes.Length == 0) { return(CsrfTokenValidationResult.TokenTamperedWith); } var newToken = new CsrfToken { CreatedDate = tokenOne.CreatedDate, RandomBytes = tokenOne.RandomBytes, }; newToken.CreateHmac(this.hmacProvider); if (!newToken.Hmac.SequenceEqual(tokenOne.Hmac)) { return(CsrfTokenValidationResult.TokenTamperedWith); } if (validityPeriod.HasValue) { var expiryDate = tokenOne.CreatedDate.Add(validityPeriod.Value); if (DateTime.Now > expiryDate) { return(CsrfTokenValidationResult.TokenExpired); } } return(CsrfTokenValidationResult.Ok); }
/// <summary> /// Creates a new csrf token with an optional salt. /// Does not store the token in context. /// </summary> /// <returns>The generated token</returns> internal static string GenerateTokenString(CryptographyConfiguration cryptographyConfiguration = null) { cryptographyConfiguration = cryptographyConfiguration ?? CsrfApplicationStartup.CryptographyConfiguration; var token = new CsrfToken { CreatedDate = DateTimeOffset.Now }; token.CreateRandomBytes(); token.CreateHmac(cryptographyConfiguration.HmacProvider); var builder = new StringBuilder(); builder.AppendFormat("RandomBytes{0}{1}", ValueDelimiter, Convert.ToBase64String(token.RandomBytes)); builder.Append(PairDelimiter); builder.AppendFormat("Hmac{0}{1}", ValueDelimiter, Convert.ToBase64String(token.Hmac)); builder.Append(PairDelimiter); builder.AppendFormat("CreatedDate{0}{1}", ValueDelimiter, token.CreatedDate.ToString("o", CultureInfo.InvariantCulture)); return(builder.ToString()); }
/// <summary> /// Validates that a cookie token is still valid with the current configuration / keys /// </summary> /// <param name="cookieToken">Token to validate</param> /// <returns>True if valid, false otherwise</returns> public bool CookieTokenStillValid(CsrfToken cookieToken) { if (cookieToken == null || cookieToken.RandomBytes == null || cookieToken.RandomBytes.Length == 0) { return false; } var newToken = new CsrfToken { CreatedDate = cookieToken.CreatedDate, RandomBytes = cookieToken.RandomBytes, }; newToken.CreateHmac(this.hmacProvider); if (!newToken.Hmac.SequenceEqual(cookieToken.Hmac)) { return false; } return true; }
/// <summary> /// Validates a pair of tokens /// </summary> /// <param name="tokenOne">First token (usually from either a form post or querystring)</param> /// <param name="tokenTwo">Second token (usually from a cookie)</param> /// <param name="validityPeriod">Optional period that the tokens are valid for</param> /// <returns>Token validation result</returns> public CsrfTokenValidationResult Validate(CsrfToken tokenOne, CsrfToken tokenTwo, TimeSpan? validityPeriod = new TimeSpan?()) { if (tokenOne == null || tokenTwo == null) { return CsrfTokenValidationResult.TokenMissing; } if (!tokenOne.Equals(tokenTwo)) { return CsrfTokenValidationResult.TokenMismatch; } if (tokenOne.RandomBytes == null || tokenOne.RandomBytes.Length == 0) { return CsrfTokenValidationResult.TokenTamperedWith; } var newToken = new CsrfToken { CreatedDate = tokenOne.CreatedDate, RandomBytes = tokenOne.RandomBytes, }; newToken.CreateHmac(this.hmacProvider); if (!newToken.Hmac.SequenceEqual(tokenOne.Hmac)) { return CsrfTokenValidationResult.TokenTamperedWith; } if (validityPeriod.HasValue) { var expiryDate = tokenOne.CreatedDate.Add(validityPeriod.Value); if (DateTime.Now > expiryDate) { return CsrfTokenValidationResult.TokenExpired; } } return CsrfTokenValidationResult.Ok; }
/// <summary> /// Validates that a cookie token is still valid with the current configuration / keys /// </summary> /// <param name="cookieToken">Token to validate</param> /// <returns>True if valid, false otherwise</returns> public bool CookieTokenStillValid(CsrfToken cookieToken) { if (cookieToken == null || cookieToken.RandomBytes == null || cookieToken.RandomBytes.Length == 0) { return(false); } var newToken = new CsrfToken { CreatedDate = cookieToken.CreatedDate, RandomBytes = cookieToken.RandomBytes, }; newToken.CreateHmac(this.hmacProvider); if (!newToken.Hmac.SequenceEqual(cookieToken.Hmac)) { return(false); } return(true); }
/// <summary> /// Creates a new csrf token with an optional salt. /// Does not store the token in context. /// </summary> /// <returns>The generated token</returns> internal static string GenerateTokenString(CryptographyConfiguration cryptographyConfiguration = null) { cryptographyConfiguration = cryptographyConfiguration ?? CsrfApplicationStartup.CryptographyConfiguration; var token = new CsrfToken { CreatedDate = DateTime.Now, }; token.CreateRandomBytes(); token.CreateHmac(cryptographyConfiguration.HmacProvider); var tokenString = CsrfApplicationStartup.ObjectSerializer.Serialize(token); return tokenString; }
public void Should_return_token_expired_if_it_has() { DateTime date = DateTime.Now.AddHours(-1); var tokenOne = new CsrfToken { CreatedDate = date, RandomBytes = new byte[] { 1, 2, 3 } }; var tokenTwo = new CsrfToken { CreatedDate = date, RandomBytes = new byte[] { 1, 2, 3 } }; tokenOne.CreateHmac(this.hmacProvider); tokenTwo.CreateHmac(this.hmacProvider); var result = this.validator.Validate(tokenOne, tokenTwo, validityPeriod: new TimeSpan(0, 30, 0)); result.ShouldEqual(CsrfTokenValidationResult.TokenExpired); }