From 8e6bee75e7b79a58a7db66c4763e5eead20bb90f Mon Sep 17 00:00:00 2001 From: Omar Roth Date: Thu, 8 Nov 2018 17:42:25 -0600 Subject: [PATCH] Add CSRF prevention for /signout --- src/invidious.cr | 26 ++++++++++++++++++++++---- src/invidious/helpers/helpers.cr | 4 ++-- src/invidious/views/template.ecr | 2 +- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/invidious.cr b/src/invidious.cr index 867a70d3..7c2b224b 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -142,6 +142,11 @@ before_all do |env| user = PG_DB.query_one?("SELECT * FROM users WHERE $1 = ANY(id)", sid, as: User) if user + challenge, token = create_response(user.email, "sign_out", HMAC_KEY, 1.week) + + env.set "challenge", challenge + env.set "token", token + env.set "user", user env.set "sid", sid end @@ -896,21 +901,34 @@ post "/login" do |env| end end -# TODO: Update this with using the same method for /clear_watch_history to prevent CSRF get "/signout" do |env| + user = env.get? "user" referer = get_referer(env) - env.request.cookies.each do |cookie| - cookie.expires = Time.new(1990, 1, 1) + if user + user = user.as(User) + + challenge = env.params.query["challenge"]? + token = env.params.query["token"]? + + begin + validate_response(challenge, token, user.email, "sign_out", HMAC_KEY) + rescue ex + error_message = ex.message + next templated "error" end - if env.get? "user" user = env.get("user").as(User) sid = env.get("sid").as(String) PG_DB.exec("UPDATE users SET id = array_remove(id, $1) WHERE email = $2", sid, user.email) + + env.request.cookies.each do |cookie| + cookie.expires = Time.new(1990, 1, 1) end env.request.cookies.add_response_headers(env.response.headers) + end + env.redirect referer end diff --git a/src/invidious/helpers/helpers.cr b/src/invidious/helpers/helpers.cr index 46b2c7b7..877a9d32 100644 --- a/src/invidious/helpers/helpers.cr +++ b/src/invidious/helpers/helpers.cr @@ -390,9 +390,9 @@ def extract_items(nodeset, ucid = nil) return items end -def create_response(user_id, operation, key) +def create_response(user_id, operation, key, expire = 6.hours) + expire = Time.now + expire nonce = Random::Secure.hex(4) - expire = Time.now + 6.hours challenge = "#{expire.to_unix}-#{nonce}-#{user_id}-#{operation}" token = OpenSSL::HMAC.digest(:sha256, key, challenge) diff --git a/src/invidious/views/template.ecr b/src/invidious/views/template.ecr index 1e31fb4a..a6191d36 100644 --- a/src/invidious/views/template.ecr +++ b/src/invidious/views/template.ecr @@ -67,7 +67,7 @@
- " class="pure-menu-heading">Sign out + &token=<%= env.get?("token") %>&challenge=<%= env.get?("challenge") %>" class="pure-menu-heading">Sign out
<% else %> " class="pure-menu-heading">Login