Skip to content

Instantly share code, notes, and snippets.

@tzkmx
Forked from dusterio/.js
Created March 11, 2021 01:15
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save tzkmx/0ce5ef7963772db4dbc9ac7200bbfa82 to your computer and use it in GitHub Desktop.
Decrypting Laravel's session cookie with JavaScript and Cloudflare
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
const string2buffer = string => {
let tempArray = new Uint8Array(string.length)
for(let i = string.length; i--) tempArray[i] = string.charCodeAt(i)
return tempArray.buffer
}
const buffer2string = buffer => {
let arr = new Uint8Array(buffer)
return String.fromCharCode.apply(String, arr);
}
const keyEncoded = 'LARAVEL_APP_KEY'
// Decrypt a Laravel cookie
async function decryptCookie(cookies) {
// Grab the encrypted cookie from the header
const matches = cookies.match(/laravel_session=([a-zA-Z0-9%=]+)/)
// URL decode it
const encrypted = decodeURIComponent(matches[1])
// Decode base64, then parse JSON
const encryptedParsed = JSON.parse(atob(encrypted))
// Decode our base64-encoded key from above
const keyDecoded = atob(keyEncoded)
// Create a key object
const key = await crypto.subtle.importKey("raw", string2buffer(keyDecoded), "AES-CBC", true, ["encrypt", "decrypt"]);
// Finally decrypt the session id
const decrypted = await crypto.subtle.decrypt({ name: "AES-CBC", iv: string2buffer(atob(encryptedParsed.iv)) }, key, string2buffer(atob(encryptedParsed.value)));
// Convert buffer to plain text and return
return buffer2string(decrypted)
}
/**
* Fetch and log a request
* @param {Request} request
*/
async function handleRequest(request) {
const requestCookies = request.headers.get('cookie')
if (! requestCookies || (! requestCookies.includes(`laravel_session=`) && ! requestCookies.includes(`remember_web_`))) {
return new Response('Missing session ID', { status: 401 })
}
// There is a Laravel session cookie, let's decode it to get the session ID
if (requestCookies.includes(`laravel_session=`)) {
let sessionId = await decryptCookie(requestCookies)
// First check in cache, if cached - return from cache
const cached = await Sessions.get(sessionId)
if (cached) return new Response(cached, { headers: { "Content-Type": "application/json" } })
}
// Otherwise, send a request to the origin server
let response = await fetch(request)
const responseCookies = response.headers.get('cookie')
// If origin responded 200 and has a new session cookie
// Decode it and save the response
if (response.ok && responseCookies && responseCookies.includes(`laravel_session=`)) {
let sessionId = await decryptCookie(responseCookies)
Sessions.put(sessionId, response.body, {expiration_ttl: 86400 * 7})
}
return response
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment