从 Chrome 扩展中获取唯一的 ClientID?

IT技术 javascript google-chrome google-chrome-extension
2021-03-14 01:44:41

我正在开发 chrome 扩展。我需要能够将每个客户识别为唯一的客户。

我无法将 guid 存储在 cookie 中,因为可以删除 cookie。我需要从系统本身读取一些独特的东西。

现在 - 我知道 JS 无法访问客户端资源(本地资源)但是 - 这是我的问题:

问题

chrome 扩展 Js 是否提供用于获取唯一客户端信息的 API(我不在乎什么数据 - 只要它是唯一的)。

编辑 :

只是为了澄清:

用户将看到一个唯一的密钥(这是他计算机的哈希数据)。此代码将发送给我,我将提供匹配结果,用户将(通过电子邮件)发送该结果,然后 - 他将能够使用扩展程序。

(不,并非所有国家/地区都支持通过钱包进行延期付款,我在这些国家/地区之一)

3个回答

为了唯一标识用户,我建议生成一个随机令牌并将其存储在您的扩展程序的存储 ( chrome.storage) 中。当存储中不存在令牌时,用户 ID 只需生成一次。

例如:

function getRandomToken() {
    // E.g. 8 * 32 = 256 bits token
    var randomPool = new Uint8Array(32);
    crypto.getRandomValues(randomPool);
    var hex = '';
    for (var i = 0; i < randomPool.length; ++i) {
        hex += randomPool[i].toString(16);
    }
    // E.g. db18458e2782b2b77e36769c569e263a53885a9944dd0a861e5064eac16f1a
    return hex;
}

chrome.storage.sync.get('userid', function(items) {
    var userid = items.userid;
    if (userid) {
        useToken(userid);
    } else {
        userid = getRandomToken();
        chrome.storage.sync.set({userid: userid}, function() {
            useToken(userid);
        });
    }
    function useToken(userid) {
        // TODO: Use user id for authentication or whatever you want.
    }
});

这种机制依赖于chrome.storage.sync,这是非常可靠的。这个存储的 ID 只会在以下情况下丢失:

  • 用户重新安装扩展。卸载扩展时将清除本地存储。
  • 已超出存储配额之一(阅读文档)。
    这不会发生,因为唯一的写操作发生在第一次运行扩展时。
  • Chrome 的存储已损坏,无法保存数据。
    即使用户没有启用 Chrome 同步,数据仍将保存在本地。Chrome 内部存在导致数据丢失的错误,但这些都是事故。
  • 用户已为您的扩展页面打开开发人员工具并运行chrome.storage.sync.clear()或类似操作。
    您无法防止拥有了解 Chrome 扩展程序内部结构知识的用户。

如果你想唯一标识一个用户,前面的方法就足够了。如果您真的想获得基于硬件的 ID,请使用chrome.storage.cpuchrome.storage.memory不过,我认为使用这些额外的资源没有任何好处,因为如果用户更换硬件,它们会发生变化,而且它们也不是唯一的(例如,两台相同的笔记本电脑会报告相同的值)。

如果生成了 UID,然后用户更改了已登录的 Google 帐户,而无需重新启动浏览器,此方法会发生什么情况?通常同步是事实的来源,但假设在另一个帐户上此扩展尚未初始化。本地状态设置了 UID,云没有记录,我希望它能够愉快地同步到第二个帐户。
2021-04-19 01:44:41
“此存储的 ID 只会在以下极少数情况下丢失” 您忘记了一种情况:只需重新安装应用程序。
2021-04-20 01:44:41
@FlashThunder 我的回答中明确提到了这句话。这是获得唯一标识符的最接近的方法。它甚至比 cookie(经常在网站上使用)更可靠。
2021-05-04 01:44:41
OP 要求识别“客户端”,这本身是模棱两可的,但随后他基本上谈到了硬件指纹。所以他大概想要local此外,虽然用户可以擦除存储,但他也可以很容易地克隆它。
2021-05-13 01:44:41
@Xan 数据确实会同步到两个 Google 帐户。这就是同一配置文件中的同步工作原理。如果用户想使用不同的帐户登录,则他们必须在“设置”页面创建一个新配置文件并登录以同步该新配置文件。同步的工作原理如下:数据存储在本地,但如果您使用 Google 帐户登录另一台设备,数据也会与另一台设备同步。如果您只想在同一台计算机上允许一个帐户,请使用chrome.storage.local代替.sync不过,这可能会让一些用户生气。
2021-05-17 01:44:41

正如 Xan 所建议的,chrome.identity API 可能是您的最佳选择。您可以获得用户的电子邮件地址并将其用作随机种子以生成您选择的代码。用户信息还包括一个“id”字段,我认为它是独一无二的,但我从未见过任何证明这一点的文档。然后,您可以使用 chrome.storage.sync API 将生成的密钥存储在您的应用程序的用户在线数据存储中。这样,用户无论何时何地登录任何设备都可以访问他们的私钥。

请注意,您必须在开发者控制台中为您的应用程序启用 oAuth2 api,并在您的应用程序清单中包含应用程序密钥和适当的范围。

这是一个粗略的例子:

function getUserInfo (interactive, callback )
{
    var xmlhttp = new XMLHttpRequest();
    var retry = true;
    var access_token;

    getToken();

    /**
     * Request the Auth Token
     */
    function getToken()
    {       
        chrome.identity.getAuthToken( { 'interactive': interactive }, function (token) {
            if ( chrome.runtime.lastError )
            {
                console.log( "ERROR! " + chrome.runtime.lastError.message );
                return;
            }
            if ( typeof token != 'undefined ')
            {
                access_token = token;
                sendRequest( );
            }
            else
                callback( );
        });

    }

    function sendRequest()
    {       
        xmlhttp.open('GET', 'https://www.googleapis.com/userinfo/v2/me' );
        xmlhttp.setRequestHeader('Authorization','Bearer ' + access_token );
        xmlhttp.onload = requestComplete;
        xmlhttp.send();
    }

    function requestComplete()
    {
        if ( this.status == 401 && retry )
        {
            retry = false; // only retry once
            console.log( "Request failed, retrying... " + this.response );
        }
        else
        {
            console.log( "Request completed. User Info: " + this.response );
            callback(null, this.status, this.response );
            var userInfo = JSON.parse( this.response );
            storeUniqueKey( userInfo );

        }
    }
}

function storeUniqueKey( info )
{
    var key;
    // TODO: Generate some key using the user info: info.loginName
    // user info here contains several fields you might find useful.
    // There is a user "id" field here which is numeric and I believe that
    // is a unique identifier that could come in handy rather than generating your 
    // own key.

    ...

    chrome.storage.sync.set ( { user_key: key } );
}

添加到 Rob W 的答案中在他的方法中,保存的字符串将传播到使用相同 Google 用户帐户登录的每个 Chrome 实例 - 有很多大大小小的 if。

如果您需要唯一标识本地用户配置文件,而不是同一 Google 用户的所有 Chrome 配置文件,您希望以chrome.storage.local相同的方式使用。但这不会是唯一的 Chrome 安装标识符 - 只是该安装中的配置文件。


还需要注意的是,所有这些数据都没有以任何方式或形式与任何事物相关联——它只是很有可能是独一无二的。但绝对没有什么能阻止用户按照他认为合适的方式阅读和克隆这些数据。在这种情况下,您无法保护客户端。


我认为更安全的方法是使用chrome.identityAPI 来请求和维护离线(因此不会过期)令牌作为许可证证明。用户无法轻松克隆此令牌存储。

我还不精通 OAuth,所以如果有人能指出这个想法有什么问题 - 欢迎他们。