Tampermonkey: GM_cookie - HttpOnly Cookie

Created on 7 Nov 2017  路  21Comments  路  Source: Tampermonkey/tampermonkey

Is possible add GM_cookie to remove/manipulate HttpOnly cookies?

```
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
removeCookies('https://www.example.com');
},
{
urls: [
"://.example.com/*"
]
}
);

enhancement

Most helpful comment

I finally found some time to implement GM_cookie. :) Please let me know if you find bugs or issues.

// ==UserScript==
// @name        GM_cookie examples
// @namespace   test
// @version     0.1
// @include     https://example.com
// @run-at      document-end
// @grant       GM_cookie
// @grant       GM.cookie
// ==/UserScript==

// GM_cookie(method, details, cb) is implemented for compatibility reasons, but due to its asynchronous nature a callback needs to be given
// * method is one of list, set and delete
// * details might contain different method-dependent properties
//   -> details.url defaults to the current documents URL 
//      Note: Tampermonkey checks if the script has @include or @match access to that URL!

GM_cookie('list', { name: 'name' }, function(cookies, error) {
    if (!error) console.log(cookies);
});

// GM_cookie.list details supports url, domain, name and path
GM_cookie.list({ url: 'https://example.com' }, function(cookies, error) {
    if (!error) console.log(cookies);

    /* logs something like this:
    [
        {
            domain: "https://example.com"
            hostOnly: true
            httpOnly: false
            name: "name"
            path: "/"
            sameSite: "no_restriction"
            secure: false
            session: true
            value: "some_value"
        }
    ]
    */
});

GM.cookie.list({ name: 'name' }).then(function(cookies) {
    console.log(cookies);
});

// GM_cookie.set details supports all properties defined here: https://developer.chrome.com/extensions/cookies#method-set
GM.cookie.set({ name: 'name', value: 'foo', httpOnly: true }, function(error) {
    console.log(error || 'success');
});

GM.cookie.set({ name: 'name', value: 'foo', secure: true })
.then(function() {
    console.log('done');
}, function(error) {
    console.log(error);
})

// GM_cookie.delete details supports url, name
GM_cookie.delete({ name: 'name' }, function() {
    console.log(error || 'success');
})

All 21 comments

You can either manipulate cookies via document.cookie or retrieve resources via GM_xhr and the anonymous option set. Besides this it's not possible to modify cookies at the moment.

However, some inspiration is here:
https://github.com/greasemonkey/greasemonkey/issues/1802
(https://github.com/janekptacijarabaci/greasemonkey/commit/dc5487ece1391e8a0a9b195f4ea02f13ed2575cc)

e.g.:

var arrayOfCookies = GM_cookie("list");
console.log(JSON.stringify(arrayOfCookies));

var trueOrThrow = GM_cookie("set", {
  "name": "cookieName",
  "value": "cookieValue",
  "path": "/path",
  "expiration": Date.parse("Jan 17, 2037") / 1000,
  "secure": true,
  "httpOnly": true,
  "session": false,
});

var countOfDeletedCookies = GM_cookie("delete", {
  "name": "cookieName", // required
  "path": "/", // optional
});

@derjanb httponly cookies can't be set or modified using document.cookie

Can I set cross domain cookie with GM_cookie or GM_xmlhttpRequest?
Because a site has domain A & domain B.
To enter domain B you have to login in domain A, but they don't has 'Allow-Control-Allow-Origin'.
So I use GM_xmlhttpRequest to simulate login on domain A, but cookie is not set on domain A.
Is there any work around to achieve it?

I finally found some time to implement GM_cookie. :) Please let me know if you find bugs or issues.

// ==UserScript==
// @name        GM_cookie examples
// @namespace   test
// @version     0.1
// @include     https://example.com
// @run-at      document-end
// @grant       GM_cookie
// @grant       GM.cookie
// ==/UserScript==

// GM_cookie(method, details, cb) is implemented for compatibility reasons, but due to its asynchronous nature a callback needs to be given
// * method is one of list, set and delete
// * details might contain different method-dependent properties
//   -> details.url defaults to the current documents URL 
//      Note: Tampermonkey checks if the script has @include or @match access to that URL!

GM_cookie('list', { name: 'name' }, function(cookies, error) {
    if (!error) console.log(cookies);
});

// GM_cookie.list details supports url, domain, name and path
GM_cookie.list({ url: 'https://example.com' }, function(cookies, error) {
    if (!error) console.log(cookies);

    /* logs something like this:
    [
        {
            domain: "https://example.com"
            hostOnly: true
            httpOnly: false
            name: "name"
            path: "/"
            sameSite: "no_restriction"
            secure: false
            session: true
            value: "some_value"
        }
    ]
    */
});

GM.cookie.list({ name: 'name' }).then(function(cookies) {
    console.log(cookies);
});

// GM_cookie.set details supports all properties defined here: https://developer.chrome.com/extensions/cookies#method-set
GM.cookie.set({ name: 'name', value: 'foo', httpOnly: true }, function(error) {
    console.log(error || 'success');
});

GM.cookie.set({ name: 'name', value: 'foo', secure: true })
.then(function() {
    console.log('done');
}, function(error) {
    console.log(error);
})

// GM_cookie.delete details supports url, name
GM_cookie.delete({ name: 'name' }, function() {
    console.log(error || 'success');
})

Does anyone have a use case that doesn't involve stealing logins? This seems like a security issue. HttpOnly cookies are usually set that way for a reason.

I don't think GM_cookies adds a new level of insecurity. Scripts can only access cookies of URLs where they are allowed to run at. And since they are allowed to run there, they can steal logins and password directly while they are entered, right? GM_cookie only allows access to potential access tokens. But of course, I'm open to discussions.

@rodorgas What is your use case for accessing HttpOnly cookies?

@Couchy @derjanb i have a case were the user id is in a HttpOnly cookie. I could take the uid from an anchor, but that would make me load fetch the page and search for it. Having a method to access that cookie would save me time

@derjanb to remove the HttpOnly cookie to 'clean' the news websites counter with soft paywall

Is this in the beta? I'm seeing "GM_cookie" is not defined

@bbshih While using this?

// @grant       GM_cookie
// @grant       GM.cookie

It's now showing up, however I'm unable to list the entire cookie. I was doing GM.cookie.list({}).then(...) but now the promise return is giving me back a "not supported" error. Do I have to have a property in the list parameter object or is {} ok?

@bbshih It's because in the recent version 4.9.5914 , the GM_cookies support is disabled.
@derjanb But why disable it? or perhaps there is a better way to get http only cookies?

Does anyone have a use case that doesn't involve stealing logins? This seems like a security issue. HttpOnly cookies are usually set that way for a reason.

@Couchy

I have a scraper that works best in a standard browser window rather than a headless one _(for fingerprinting reasons)_, and the site that it scrapes accumulates extra cookie-info on each request, leading to a 400 Bad Request - Request Header Or Cookie Too Large every X requests.

Without GM_cookie, I either have to elevate to an extension _(a little overboard for this relatively-simple scraper)_, pursue other possibilities, or continue manually clearing cookies. It's the delete functionality that I'd get the most use from.

How can I use GM_cookie?
Is it usable in current release version?

is GM_cookie was removed in stable version? @derjanb

is GM_cookie was removed in stable version? @derjanb

stable version never supported, but beta version has been doing

@derjanb when will this feature be available in the stable version?

for chrome, there is chrome.cookies.<method> https://developer.chrome.com/extensions/cookies

if the userscript platform does not support it, I have to upgrade userscript to a browser extension.

Two improvements:

  • Make GM_cookie.delete pass cookie object which it received to delete into callback to be able to perform some other actions with it. GM.cookie.delete should return a promise and pass the same object as a result.
  • Hide own TM_... cookies during a startup since apparently script at document-start with instant injection mode can occasionally see and remove them.

Sorry for bumping, but are there any updates on mainlining this?

My use case for this is to support sites like twitter which add CSRF checks through cookies to their API calls (the value of a csrf cookie needed to be present in the headers). Yes it's possible to access those cookies through document.cookie (they're not httponly, and can't be as their client-side code requires reading them), but only if the user is on that page (twitter.com). My script needs to perform those API calls on any page (wherever there's a link to twitter etc. that the user wants to pop up). While I'm able to support this for the extension version of my script, I'd like to be able to offer the same functionality for userscript users.

Thanks for your work on this!

Was this page helpful?
0 / 5 - 0 ratings