views:

249

answers:

7

I have a user on website A and I need to log him to website B (not under my control) but without jeopardizing his password on website B. Website B doesn't have an API which is what's making this more complicated than should be.

My first option is to render my own form on website A, user enters his website B password into my form, and I somehow securely pass his website B password to website B to log him in. This means I have to first pass the password securely from the client to my server, then pass it again securely from my server to the end website. That's what I'm guessing I have to do, but I don't have a plan for how to implement these 2 hops securely, so I worry that I might expose the user's password somehow.

So I thought of the second option which is to render the same website B from website B onto my website. But the form on website B is part of a larger page, so can this be done?

  • How would I isolate the code for the form itself from the code for the full page
  • how to present the form on my website. I want the user to see it. iframe comes to mind but never worked with it
  • will the form still be valid when the user clicks the submit button or does rendering the form on my website somehow invalidates it

These are the 2 different solutions I thought of. I welcome answers for each of them, and also welcome answers that suggest an alternate third approach that may be easier.

+1  A: 

To isolate the form from the larger page, find the <form> and </form> tags, and only copy any and elements between them. Now put that form on your page, with its action still pointing to the URL it was pointing to on the original website. The password never goes through your server.

Dan Grossman
+2  A: 

I'm not really getting what you want to do, if it is just logging into the site you can maybe do something like this:
Mainsite:

<iframe id="logon" src="/logonto-other.html"></iframe>

/logonto-other.html:

<form onsubmit="top.logon.style.visibility='none';" action="http://other-site.com/login" method="post">
  <dl>
    <dt><label for="user">Name</label></dt>
      <dd><input name="user" />
    <dt><label for="pass">Password</label></dt>
      <dd><input name="pass" />
  </dl>
  <?php //code that acquires hash from other site
    // Don't know site B so can't write this one yet.
  ?>
  <input type="submit" value="Login" />
</form>

This way the user will just be logged into the other site, your interaction abilities with it would still be limited (or should, I think, I never learned the same-origin policies as I have never felt that there is any restriction to what I do. Maybe todays browsers are stricter).

About the "2 hop" thing, do you have a certificate and SSL/HTTPS support on your server A? Does server B have this? Do you think you can make the users trust you on having their password? One tip would be that you add a paragraph explaining the situation and a link there the user can contact site B to add pressure on them to implement OAuth and / or OpenID?

It might be possible to path something up nicely, even if you don't have HTTPS on your server you can use JavaScript or an Java applet to encrypt the password (there has to be PGP in JavaScript somewhere on the net. Although, if the browsers addressbar turns green, the users have an easier decision whether or not to trust you.

Would Like some answers to my questions, and can we be allowed to know what Site B is? And what exactly you try to do, maybe we can work this out together.

Wish you good luck.

Frank
+6  A: 

As long as you are using SSL on your site, there's not a significant risk in terms of compromising the user's password (unless you are doing financial transactions of some sort, then please clarify).

My suggestion would be, don't copy their form. Instead, replicate the HTTP POST generated by that form. You can do this completely programmatically and the user will never leave YOUR site, but (in most cases) the result will be that the user is logged in to THEIR site as well.

If there is some sort of hashed fields to deal with, request their form page (programatically) and use whatever values you receive to send back to the second site so that the request will validate. Their server doesn't know that the request isn't coming from a browser (indeed, you can add a user agent to the HTTP headers if you wish).

I have used this methodology against Verizon's site and LinkedIn (both for legitimate purposes) and it works.

To recap:

1) Learn the structure of their HTTP POST.

2) Add a login form to YOUR site.

3) Manipulate the request in your code to look like the POST their site expects.

4) POST to their site from your code.

5) Display the response to the user on your site (if needed), redirect, whatever.

Tim
+3  A: 

It all depends on how the server you are POSTing to handles CSRF [Cross-Site Request Forgeries], as that is basically what you are doing. If they are using a Django that is relatively recent, for instance, then POST requests from an outside server will by default fail, unless they contain the csrf cookie value.

It is possible to get around this, if you have control of the server you are POSTing to as well.

Matthew Schinckel
Is the csrf token an issue with both options I outlined above or is it only a concern for one of them?
Berming
Likely for both. The way Django works is that every POST request requires a csrf_token field, that matches the one in the session that the browser has established. Essentially, what you are doing in both cases is the same: you are creating your own form that mirrors the data that is required. This is exactly what CSRF protection is supposed to protect against.
Matthew Schinckel
Having said that, it is likely, depending on the age of the site (and the person who built it), that there is no CSRF protection.
Matthew Schinckel
+3  A: 

Hello,

I'll try to outline a solution, but it may not be correct, or even what you wanted and it definitely is impractical.

From what I know about XSRF if the destination site did its homework you will not be able to mimic a form submit from your domain.

The only one that has access to the user credentials, apart from the target site, is the browser. So what you actually need to do is become a browser. This means that you must convince the user that he can hand you his login information to the other site. I have no idea how you can do that, I for one wouldn't trust something like that. (Another option would be to trick him (phishing), but that is illegal and I don't think you would even consider it.)

After you manage to convince the user to give you his data you'll still have to act like a browser. You'll have to implement a system for storing cookies for each user so that a session can be created when you log in.

After doing so you will be logged in with the user's data, but the user won't be. So you will need to implement any other operation the user would need through your site as well.


What I recommend:

Either contact the destination site and set up a protocol that you can use to authenticate the user from your site. There are some really cool iframe techniques to do that. Read this article for a competent presentation http://softwareas.com/cross-domain-communication-with-iframes .

Or make the user open a popup with the login page to that site. Make sure the popup has the address bar visible.

Alin Purcaru
+1 good tips. What protocol do you suggest I try to setup with the site?
Berming
See the article I added to the post.
Alin Purcaru
+1  A: 

See: Sockets

  1. Study SiteB's login form HTML to gather a list of field names, expected values, and action url.
  2. Remake the form on your own site, using same field names. Action url should point to a handling script on your own server. A caveat at this point is if Site B uses some special token field or cookie set when their login form page loads. If that's the case, use sockets to connect to and get a new copy of Site B's login page. You'll need to know HTTP message standards and proper request body structure to pull this off. Then, parse the retrieved text for the token field or cookie names and values to be used on your own page.
  3. User inputs their username and password for Site B on your form. On submit, form results are passed to your handler script.
  4. Your handler script uses Sockets to connect to Site B's action url target as a regular POST request. This POST request includes any cookies and token names/values Site B gave it in the previous few steps. You'll need to follow HTTP protocol message structure guidelines again to pull this off.
  5. Site B authenticates using your user's info. Your handler script is sitting there waiting for a response.
  6. Site B responds to handler script. You'll need to study typical responses Site B returns to know how to parse any response text (and again learn how to parse HTTP messages), including returned cookie headers.
  7. Your handler script needs to keep a log somewhere matching the user with any cookie values returned after successful authentication by Site B. On any future requests to Site B, use sockets again to mascaraed as the user, passing the cookie header/val used to ID their (IE: your) login session to Site B.

Keep in mind you may want to keep an open and honest dialog about what you're doing with Site B, or you could be liable for civil action.

bob-the-destroyer
A: 

The scenario you are describing can be tricky to impossible. The main problem you are facing is about how you post the login credentials to site B in such a way that the cookies returned by the successful login itself end up in the user's browser and belong to site B, so that site B gets them when the user actually navigates there.

A couple of people have suggested to have the form posted to a PHP file on your server and let that do the login from server to server. This solution almost never works. Even if site B accepts your server-server login (which it probably will, as you can fake any browser you want), it will be your webserver which will be getting the new cookies, and your webserver's IP which the session will be associated with. Even if you return the cookie to the browser, it will save it for your site (site A) and won't submit it to site B when the browser gets there, so the user will stay logged out of site B.

So, the only thing you can do here is to host a login form for their site on your server. This means that you will have to send out a form to the browser which has an ACTION that points to site B's login form. This also means that whenever the user clicks the login button, the control is transferred to site B: the user will be navigating away from your site and you lose him.

There are 2 major technical problems with this second method: one is that site B might have XSS prevention and may actually block you from posting stuff to their login page. The other problem is that if your site is on SSL, browsers will be nagging big time for you submitting a form to a different website. None of these is something you can solve yourself.

The only clean solution would be to really sit down with site B and make some plan about a common authentication, or at least an authentication API. You can try the form crossposting solution but chances are good that you'll have problems with it you don't like.

CodeTwice