使用 JavaScript 向 API 发出的请求未经过身份验证

问题描述 投票:0回答:1

我想做的是在浏览器中执行 JavaScript 代码,向 Roblox API 发送 GET 请求https://economy.roblox.com/v1/user/currency 获取 Robux(游戏内货币)我的 Roblox 帐户中的游戏 Roblox)金额。问题是,当我打开 roblox.com 的选项卡并执行 JavaScript 代码来获取 Robux 金额时,对 API 的请求将不会经过身份验证。 (请求中缺少 .ROBLOSECURITY 会话 cookie)

问题是,打开economic.roblox.com 选项卡将允许对 /v1/user/currency 的请求进行身份验证,但我需要在 roblox.com 网站上执行我的任务。在 roblox.com 中时,有什么方法可以向economic.roblox.com 发送经过身份验证的请求吗?

不,我不能只获取我帐户的 .ROBLOSECURITY cookie,然后手动将其包含在 JavaScript 代码中以将其发送到 API,这是我不能这样做的原因。

我想到的一种方法是让 JavaScript 代码重定向我或打开economic.roblox.com 的选项卡一瞬间发送 API 请求,然后重定向回我所在的 roblox.com 网址,但是这不起作用,因为如果我被重定向到另一个网址,正常的浏览器行为会阻止其余 JavaScript 代码的执行。

javascript request roblox
1个回答
0
投票

过去几天我一直在解决类似的问题,这是我提出的解决方案(完全归功于 Github 上的Julli4n 的蝙蝠生成代码

javascript:(

function(){

function arrayBufferToBase64String(arrayBuffer){
    let res = "";
    const bytes = new Uint8Array(arrayBuffer);
    for (let i = 0; i < bytes.byteLength; i++) {
        res += String.fromCharCode(bytes[i]);
    };
    return btoa(res);
};
async function hashStringSha256(str){
    const uint8 = new TextEncoder().encode(str);
    const hashBuffer = await crypto.subtle.digest("SHA-256", uint8);
    return arrayBufferToBase64String(hashBuffer);
};

async function signWithKey(privateKey, data){
    const bufferResult = await crypto.subtle.sign(
        {name: "ECDSA",hash: { name: "SHA-256" }},
        privateKey,
        new TextEncoder().encode(data).buffer
    );
    return arrayBufferToBase64String(bufferResult);
};

async function getCryptoKeyPairFromDB(dbName,dbObjectName,dbObjectChildId){
    let targetVersion = 1;
    /*we want Roblox to create the DB on their end, so we do not want to interfere*/
    if ("databases" in indexedDB) {
        const databases = await indexedDB.databases();
        const database = databases.find((db) => db.name === dbName);
        if (!database) {
            return null;
        }
        if (database?.version) {
            targetVersion = database.version;
        }
    };
    return new Promise((resolve, reject) => {
        const request = indexedDB.open(dbName,targetVersion);
        request.onsuccess = () => {
            try {
                const db = request.result;
                const transaction = db.transaction(dbObjectName, "readonly");
                const objectStore = transaction.objectStore(dbObjectName);
                const get = objectStore.get(dbObjectChildId);
                get.onsuccess = () => {
                    resolve(get.result);
                };
                get.onerror = () => {
                    reject(request.error);
                };
                transaction.oncomplete = () => {
                    db.close();
                };
            } catch (err) {
                reject(err);
            }
        };
        request.onerror = () => {
            reject(request.error);
        }
    })
};


async function generateBAT(body){
        const pair = await getCryptoKeyPairFromDB("hbaDB","hbaObjectStore","hba_keys");
        
        if (!pair?.privateKey) {
            return null;
        };
        const timestamp = Math.floor((Date.now()+1000) / 1000).toString();
        let strBody;
        if (typeof body === "object") {
            strBody = JSON.stringify(body);
        } else if (typeof body === "string") {
            strBody = body;
        };

        const hashedBody = await hashStringSha256(strBody);
        const payloadToSign = [hashedBody, timestamp].join("|");
        const signature = await signWithKey(pair.privateKey, payloadToSign);

        return [hashedBody, timestamp, signature].join("|");
    };


/*-------------*/

token = document.getElementsByName("csrf-token")[0].dataset.token;

body = "";
obody = "";

headers = {
    "x-csrf-token":token,
    "x-bound-auth-token" : "",
    "accept":"application/json"};

bat = generateBAT(body);
bat.then((tok) => {
headers["x-bound-auth-token"] = tok
});
  
const fetchPromise = fetch("https://economy.roblox.com/v1/user/currency",
  {"headers":headers,
  "method":"GET",
  "credentials": "include"}
);

fetchPromise
  .then((response) => {
    if (!response.ok) {
        heastr = "";
        
        token = response.headers.get("x-csrf-token");
      throw new Error(`HTTP error: ${response.status+response.statusText}`);
    };
    return response.json();
  })
  .then((data) => {
    alert(JSON.stringify(data));
  })
  .catch((error) => {
    alert(`Could not get... anything: ${error}`);
    alert(JSON.stringify(headers));
    alert(body);
  });

}());
© www.soinside.com 2019 - 2024. All rights reserved.