Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to authenticate/identify different users? #73

Open
flippyhead opened this issue Mar 9, 2016 · 12 comments
Open

Is it possible to authenticate/identify different users? #73

flippyhead opened this issue Mar 9, 2016 · 12 comments

Comments

@flippyhead
Copy link

What's the recommended way to do authentication to the proxy?

@felicienfrancois
Copy link
Collaborator

There is nothing implemented about authentication in node-http-mitm-proxy so you'll have to do it on your own.

Basically, you should use Proxy Authentication which is a based on HTTP Authentication.

  • on request, if the client is not authenticated send a 407 Response with a Proxy-Authenticate header indicating the auth method (basic or digest), using the same syntax than WWW-Authenticate header for HTTP authentication.
  • then, the client will emit another request with a Proxy-Authorization header which contains the identification data, using the same syntax than WWW-Authorisation header for HTTP authentication. You check it and remove it before forwarding to the target server.

@flippyhead
Copy link
Author

OK great thank you. I'm actually trying to have a single proxy serve multiple users. I assume I can implement cookie based session tracking in a similar way to track who's logged in etc?

@felicienfrancois
Copy link
Collaborator

Cookie tracking may be hard to implement because cookies are per domain. So if you set a cookie when the user is on google.com, the client wont send you back when he will be on twitter.com.

The only solution I see would be to synchronise cookies through a single domain, using redirects when the cookie is not present, but this is not trivial and would introduce delays. Basically:

  • If the tracking cookie is not present => Redirect to a predifined domain http://mayfakedomain.com/cookiesync?url=http://originalurl.com/some.html
  • On mayfakedomain.com, you should get the tracking cookie or set it if not exist (with Set-cookie header)
  • Redirect to http://originalurl.com/myproxy-set-tracking-cookie?url=http://originalurl.com/some.html&track-cookie=XXXXXXXXXXXXX
  • Set the cookie on the originalurl.com host (using Set-cookie header) and redirect back to http://originalurl.com/some.html

It means 3 Redirects (may be done in 2 but risky) on each new domains. Additionally there is a few traps to avoid like

  • encoding of original url
  • infinite redirects if cookies are disabled.
  • secure flag of cookies
  • wilcard cookies

@flippyhead
Copy link
Author

Eek, that sounds pretty bad. I guess I can make a unique subdomain for each proxy user, which is created only after they authenticate but then used thereafter.

@flippyhead
Copy link
Author

But actually I'm not even sure how to get the URL used for the proxy in any of the request callbacks.

@felicienfrancois
Copy link
Collaborator

You can have a single fake domain for the cookie synchronisation. The value of the cookie identify your users.
Something like that:

proxy.onRequest(function(ctx, callback) {
  var trackingCookie = ctx.clientToProxyRequest.headers['cookies']['my-proxy-tracking-cookie'];
  if (ctx.clientToProxyRequest.headers.host === "myproxysyncdomain.com") {
    var targetUrl = // TODO : extract targetUrl from query string
    var responseHeaders = {};
    if (!trackingCookie) {
      trackingCookie = // TODO : generate a unique identifier for the session
      responseHeaders['Set-Cookie'] = 'my-proxy-tracking-cookie=' + trackingCookie
    }
    responseHeaders['Location'] = targetUrl.host + '/myproxy-set-tracking-cookie?trackingCookie='+trackingCookie+'&targetUrl='+targetUrl; // TODO: encode for url instead of simply concatenating
    ctx.clientToProxyResponse.writeHead(302, responseHeaders);
    response.end();
    return ; // Don't call callback
  }
  if (ctx.clientToProxyRequest.url.indexOf('/myproxy-set-tracking-cookie') === 0) {
    var targetUrl = // TODO : extract targetUrl from query string
    var trackingCookie = // TODO : extract trackingCookie from query string
    ctx.clientToProxyResponse.writeHead(302, {
      'Set-Cookie' : 'my-proxy-tracking-cookie=' + trackingCookie,
      'Location' : targetUrl
    });
    response.end();
    return ; // Don't call callback
  }
  if (!trackingCookie) {
    var currentUrl = // TODO : resolve absolute request url from isSSL + host + url (see examples) 
    ctx.clientToProxyResponse.writeHead(302, {
      'Location' : "http://myproxysyncdomain.com/?targetUrl="+currentUrl // TODO: encode for url instead of simply concatenating
    });
    response.end();
     return ; // Don't call callback
  }
  // Here you have a trackingCookie set, do your normal job
  // TODO: remove the tracking cookie from ctx.proxyToServerRequestOptions.headers
  // and forward
  callback();
});

@felicienfrancois
Copy link
Collaborator

Here an example of the process:

  • First request to a domain (ex: https://google.com/search?q=something)
  • => there is no tracking cookie yet on google domain
  • => Redirect to http://myproxysyncdomain.com?targetUrl=https%3A%2F%2Fgoogle.com%2Fsearch%3Fq%3Dsomething
  • => You get the traking cookie set on myproxysyncdomain.com
  • => if it is not yet set it means this is a new user => Create a new unique cookie value that identify the user (ex: 65fd68hg6az0sd) and set it on myproxysyncdomain.com using the 'Set-Cookie' header
  • => Redirect to https://google.com/myproxy-set-tracking-cookie?trackingCookie=65fd68hg6az0sd&targetUrl=https%3A%2F%2Fgoogle.com%2Fsearch%3Fq%3Dsomething
  • => Then set the tracking cookie on google.com (passed through parameters) using Set-Cookie header
  • => Redirect to the original url (passed through parameters) https://google.com/search?q=something

@flippyhead
Copy link
Author

OK very interesting. The other approach I'm considering is simply to provide each user a unique proxy address. Something like https://65fd68hg6az0sd.myproxy.com. They'd need to login use basic auth but then I could simply use the unique subdomain to manage the sessions. Could this work? The only trouble I'm seeing is not knowing how to get the proxy address in the request. I can see the address of the resources they are requesting of course, but haven't yet found where the proxy address is recorded.

@felicienfrancois
Copy link
Collaborator

I you use proxy basic auth (like suggested in #73 (comment)), you would probably have the Proxy-Authorization header on each request so you can use it to track your users. You don't need a custom proxy domain for each users.

@flippyhead
Copy link
Author

Interestingly (and frustratingly) OSX and iOS does not do this but FireFox will, so it seams implementation of the spec is not consistent. It looks like I'll need a mixed strategy, possibly using your excellent cookie based approach along with a URL based identifier. Do you know where I might see what host/URL is being used for the current proxy request?

Thanks again for all your help!

@felicienfrancois
Copy link
Collaborator

... not adding Proxy-Authorization header preemptively ...

This means that the first request wont have the Proxy-Authorization header.

When ever i send a 407 proxy-authentication required, it will send back correct credentials

But if you send a 407 error with a Proxy-Authenticate header, the client will send it to all next requests.

Firefox or any other clients probably do the same because there is several syntax for the value of Proxy-Authorization header (basic or digest). The client cannot guess which syntax is expected by the proxy until it recieve the info from a 407 error with a Proxy-Authenticate header.

Normally, the client should ask for proxy credentials only once and save it for next proxy authentication requests.

@felicienfrancois
Copy link
Collaborator

Do you know where I might see what host/URL is being used for the current proxy request

Not sure it is possible.
Maybe at the connect step.
But there is no hook for it in the node-http-mitm-proxy API

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants