summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorleonklingele <git@leonklingele.de>2020-03-02 17:04:36 +0100
committerGitHub <noreply@github.com>2020-03-02 10:04:36 -0600
commit0d536d11e3d816802f4e6c569ef56d43140710aa (patch)
treef43e52b7b479d37728f7caa5352b4522a1b3cf10
parent72a4962fd00076189270daefb1e217d9d68fc50e (diff)
downloadinvidious-0d536d11e3d816802f4e6c569ef56d43140710aa.tar.gz
invidious-0d536d11e3d816802f4e6c569ef56d43140710aa.tar.bz2
invidious-0d536d11e3d816802f4e6c569ef56d43140710aa.zip
Verify token signature in constant time, Run cheap checks first in token validation process (#1032)
* Verify token signature in constant time To prevent timing side channel attacks * Run cheap checks first in token validation process Expensive checks such as the nonce lookup on the database or the signature check can be run after cheap/fast checks.
-rw-r--r--src/invidious/helpers/tokens.cr29
1 files changed, 15 insertions, 14 deletions
diff --git a/src/invidious/helpers/tokens.cr b/src/invidious/helpers/tokens.cr
index 30f7d4f4..0b609e80 100644
--- a/src/invidious/helpers/tokens.cr
+++ b/src/invidious/helpers/tokens.cr
@@ -1,3 +1,5 @@
+require "crypto/subtle"
+
def generate_token(email, scopes, expire, key, db)
session = "v1:#{Base64.urlsafe_encode(Random::Secure.random_bytes(32))}"
PG_DB.exec("INSERT INTO session_ids VALUES ($1, $2, $3)", session, email, Time.utc)
@@ -76,32 +78,31 @@ def validate_request(token, session, request, key, db, locale = nil)
raise translate(locale, "Hidden field \"token\" is a required field")
end
- if token["signature"] != sign_token(key, token)
- raise translate(locale, "Invalid signature")
+ expire = token["expire"]?.try &.as_i
+ if expire.try &.< Time.utc.to_unix
+ raise translate(locale, "Token is expired, please try again")
end
if token["session"] != session
raise translate(locale, "Erroneous token")
end
- if token["nonce"]? && (nonce = db.query_one?("SELECT * FROM nonces WHERE nonce = $1", token["nonce"], as: {String, Time}))
- if nonce[1] > Time.utc
- db.exec("UPDATE nonces SET expire = $1 WHERE nonce = $2", Time.utc(1990, 1, 1), nonce[0])
- else
- raise translate(locale, "Erroneous token")
- end
- end
-
scopes = token["scopes"].as_a.map { |v| v.as_s }
scope = "#{request.method}:#{request.path.lchop("/api/v1/auth/").lstrip("/")}"
-
if !scopes_include_scope(scopes, scope)
raise translate(locale, "Invalid scope")
end
- expire = token["expire"]?.try &.as_i
- if expire.try &.< Time.utc.to_unix
- raise translate(locale, "Token is expired, please try again")
+ if !Crypto::Subtle.constant_time_compare(token["signature"].to_s, sign_token(key, token))
+ raise translate(locale, "Invalid signature")
+ end
+
+ if token["nonce"]? && (nonce = db.query_one?("SELECT * FROM nonces WHERE nonce = $1", token["nonce"], as: {String, Time}))
+ if nonce[1] > Time.utc
+ db.exec("UPDATE nonces SET expire = $1 WHERE nonce = $2", Time.utc(1990, 1, 1), nonce[0])
+ else
+ raise translate(locale, "Erroneous token")
+ end
end
return {scopes, expire, token["signature"].as_s}