fix cookie

This commit is contained in:
rulingcom 2023-04-08 10:09:37 +08:00
parent 2528857aa7
commit 91f8230e28
2 changed files with 113 additions and 2 deletions

View File

@ -34,12 +34,48 @@ class Roda
# Proxies the request, forwarding all headers except +Host+ which is # Proxies the request, forwarding all headers except +Host+ which is
# rewritten to be the destination host. The response headers, body and # rewritten to be the destination host. The response headers, body and
# status are returned to the client. # status are returned to the client.
def verify_and_decrypt_session_cookie(cookie, secret_key_base)
cookie = CGI.unescape(cookie)
#################
# generate keys #
#################
encrypted_cookie_salt = 'encrypted cookie' # default: Rails.application.config.action_dispatch.encrypted_cookie_salt
encrypted_signed_cookie_salt = 'signed encrypted cookie' # default: Rails.application.config.action_dispatch.encrypted_signed_cookie_salt
iterations = 1000
key_size = 64
secret = OpenSSL::PKCS5.pbkdf2_hmac_sha1(secret_key_base, encrypted_cookie_salt, iterations, key_size)[0, OpenSSL::Cipher.new('aes-256-cbc').key_len]
sign_secret = OpenSSL::PKCS5.pbkdf2_hmac_sha1(secret_key_base, encrypted_signed_cookie_salt, iterations, key_size)
##########
# Verify #
##########
data, digest = cookie.split('--')
raise 'invalid message' unless digest == OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, sign_secret, data)
# you better use secure compare instead of `==` to prevent time based attact,
# ref: ActiveSupport::SecurityUtils.secure_compare
###########
# Decrypt #
###########
encrypted_message = Base64.strict_decode64(data)
encrypted_data, iv = encrypted_message.split('--').map{|v| Base64.strict_decode64(v) }
cipher = OpenSSL::Cipher.new('aes-256-cbc')
cipher.decrypt
cipher.key = secret
cipher.iv = iv
decrypted_data = cipher.update(encrypted_data)
decrypted_data << cipher.final
Marshal.load(decrypted_data)
end
def proxy def proxy
client = NetX::HTTPUnix.new(_sock_url) client = NetX::HTTPUnix.new(_sock_url)
request_class = Net::HTTP.const_get(:"#{env['REQUEST_METHOD'].to_s.downcase.capitalize}") request_class = Net::HTTP.const_get(:"#{env['REQUEST_METHOD'].to_s.downcase.capitalize}")
req = request_class.new(_proxy_url.to_s, _proxy_headers) req = request_class.new(_proxy_url.to_s, _proxy_headers)
env_body = env["rack.input"].read env_body = env["rack.input"].read
env_content_type = env['CONTENT_TYPE'] env_content_type = env['CONTENT_TYPE']
secret_key_base = YAML.load(File.read(File.expand_path("../../../../config/secrets.yml",__FILE__)))['production']['secret_key_base']
unless env_body.nil? unless env_body.nil?
req.body = env_body req.body = env_body
end end
@ -48,6 +84,21 @@ class Roda
end end
f_response = client.request(req) f_response = client.request(req)
f_response.content_length = nil #prevent duplicate header Content-Length and content-length f_response.content_length = nil #prevent duplicate header Content-Length and content-length
# if env['REQUEST_METHOD'].to_s.downcase == 'post'
# cookie = f_response['set-cookie'].to_s.split(/[;,]\s?/).map do |s|
# k,v = s.split('=', 2)
# [k, v.to_s]
# end.to_h
# puts ["cookie", cookie]
# if cookie['_orbit_store_session']
# secret_key_base = YAML.load(File.read(File.expand_path("../../../../config/secrets.yml",__FILE__)))['production']['secret_key_base']
# puts verify_and_decrypt_session_cookie(cookie['_orbit_store_session'], secret_key_base) rescue {}
# puts "---------------------------------"
# print f_response.get_fields('set-cookie') #['set-cookie']
# puts nil
# puts "================================="
# end
# end
_respond(f_response) _respond(f_response)
end end
@ -104,9 +155,20 @@ class Roda
def _respond(proxied_response) def _respond(proxied_response)
response.status = proxied_response.code.to_i response.status = proxied_response.code.to_i
proxied_response proxied_response
.each_header.to_h .to_hash
.reject { |k, v| k.downcase == 'transfer-encoding' } .reject { |k, v| k.downcase == 'transfer-encoding' }
.each { |k, v| response[k] = v } .each { |k, v| response[k] = v.join("\n") }
# cookie = proxied_response['set-cookie'].to_s.split('; ').map{|s| k,v = s.split('='); [k, v.to_s]}.to_h
# if cookie['_orbit_store_session']
# secret_key_base = YAML.load(File.read(File.expand_path("../../../../config/secrets.yml",__FILE__)))['production']['secret_key_base']
# puts verify_and_decrypt_session_cookie(cookie['_orbit_store_session'], secret_key_base) rescue {}
# end
# puts proxied_response
# .each_header.to_h
# proxied_response['set-cookie'].split('; ').map do |s|
# k,v = s.split('=')
# response.set_cookie(k,v)
# end
response.write(proxied_response.body) response.write(proxied_response.body)
end end

49
lib/session_store.rb Normal file
View File

@ -0,0 +1,49 @@
# Be sure to restart your server when you modify this file.
require 'rack/utils'
module Rack
module Utils
def self.set_cookie_header!(header, key, value)
case value
when Hash
domain = "; domain=" + value[:domain] if value[:domain]
path = "; path=" + value[:path] if value[:path]
max_age = "; max-age=" + value[:max_age] if value[:max_age]
expires = "; expires=" +
rfc2822(value[:expires].clone.gmtime) if value[:expires]
secure = "; secure" if value[:secure]
httponly = "; HttpOnly" if value[:httponly]
same_site =
case value[:same_site]
when false, nil
nil
when :none, 'None', :None
'; SameSite=None'
when :lax, 'Lax', :Lax
'; SameSite=Lax'
when true, :strict, 'Strict', :Strict
'; SameSite=Strict'
else
raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}"
end
value = value[:value]
end
value = [value] unless Array === value
cookie = escape(key) + "=" +
value.map { |v| escape v }.join("&") +
"#{domain}#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}"
case header["Set-Cookie"]
when nil, ''
header["Set-Cookie"] = cookie
when String
header["Set-Cookie"] = [header["Set-Cookie"], cookie].join("\n")
when Array
header["Set-Cookie"] = (header["Set-Cookie"] + [cookie]).join("\n")
end
nil
end
end
end
#Orbit::Application.config.session_store :cookie_store, key: '_orbit_store_session', expire_after: 1.week, same_site: :lax, path: "/", httponly: true
Orbit::Application.config.session_store :cookie_store, key: '_orbit_store_session', same_site: :lax, path: "/", httponly: true