Skip to content

Instantly share code, notes, and snippets.

@rishavs
Created October 18, 2020 20:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rishavs/c7d3cd2a4718ab39ba6fa715e6a028ae to your computer and use it in GitHub Desktop.
Save rishavs/c7d3cd2a4718ab39ba6fa715e6a028ae to your computer and use it in GitHub Desktop.
CSRF protection in Crystal
# Embed this as a <input type="hidden"> into *every form*
def csrf_token(session_id, key = ENV_CSRF_TOKEN_SECRET)
d = OpenSSL::Digest.new("SHA256")
d.update session_id.to_slice
payload = String.build do |s|
s << d.hexdigest
s << " "
s << Time.utc.to_unix
end
"#{OpenSSL::HMAC.hexdigest(CSRF_TOKEN_HMAC_ALGO, key, payload)} #{payload}"
end
# Verify the token of *every posted form* before trusting the input
def verify_csrf_token!(session_id, token, key = ENV_CSRF_TOKEN_SECRET, ttl = ENV_CSRF_TOKEN_TTL)
hmac, sid_digest, timestamp = token.split(" ")
correct_hmac = OpenSSL::HMAC.hexdigest(CSRF_TOKEN_HMAC_ALGO, key, "#{sid_digest} #{timestamp}")
raise InvalidCSRFToken.new("CSRF token is corrupt") unless correct_hmac == hmac
raise InvalidCSRFToken.new("CSRF token is expired") unless Time.utc.to_unix + ttl > timestamp.to_i
correct_sid_digest = OpenSSL::Digest.new("SHA256")
correct_sid_digest.update session_id.to_slice
raise InvalidCSRFToken.new("CSRF token does not match session") unless correct_sid_digest.hexdigest == sid_digest
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment