I have a website that is served via HTTP with a custom domain (e.g., mywebsite.com) on Heroku.
When a user wants to login, I redirect them to my Heroku application's non-custom URL via HTTPS (using Piggyback SSL, because I am cheap and don't want to pay for SSL Endpoint).
Then, after they've logged in, I redirect the user back to my custom domain since their traffic doesn't really need to be encrypted anymore.
Only problem is that before redirecting them, I display a message (e.g., "You've successfully logged in!") using flash[:notice] (with sinatra-flash). But I believe that since the user crosses from one domain to another in this process, though still on the same server, they don't see the message since their session data from domain X is not accessible from domain Y.
Is my understanding of the problem correct?
What is the right way to fix it?
Update on 2012-10-12:
So, the solution I ended up going with is a little hacky:
First, I added a new data model, OneTimeFlash, with a token field containing a random string for each record. Then I made it so that after the user logs in on domain X, I create a new OneTimeFlash instance and redirect to domain Y with the token in the query string:
# The model automatically generates a token before being created.
one_time_flash = OneTimeFlash.create(:message => "You've successfully logged in!")
redirect "#{DOMAIN_Y}/flash/#{one_time_flash.token}"
Then when the server detects this token in the request, it displays the flash:
get "/flash/:token" do |token|
one_time_flash = OneTimeFlash.first(:token => token)
flash[:notice] = one_time_flash.message unless one_time_flash.nil?
one_time_flash.destroy
redirect "/
end
(The ORM is DataMapper, in case anyone's confused.)
Like I said: it's hacky, but it works. Can anyone think of any serious problems with this approach?
you can't use flash between domains in that situation since flash is only saved for the next request.
you could use HTML5 localstorage - some random localstorage explanation or w3schools website on html5 localstorage
Related
I have very little experience with APIs which is something that I'm trying to change so I'm trying to get started with the Tumblr api. I've installed the tumblr_client gem (documentation here) and am following the instructions. I've created an application on a new Tumblr account and have the necessary OAuth information (consumer_key, consumer_secret, ect.) Actually getting it to do something is proving difficult, so like a good little programmer I'm trying to get the console going to explore a bit.
This requires a bit of setup, so I'm following the instructions here:
The first time that you go to use the irb console, if you have no
.tumblr file, it will walk you through the process of generating one.
You will be prompted for your consumer_key and consumer_secret (which
you can get here: http://www.tumblr.com/oauth/register) and then sent
out to the site to verify your account. Once you verify, you will be
redirected to your redirect URL (localhost by default) and copy the
oauth_verifier back into the console. Then you're all set!
I'm prompted for my key and secret, then I go to the URL where I'm supposed to give authorization. Tumblr gives me a popup which reads "Is it alright for this application to access some of your data and make posts to your account? You are logged in as example#example.com" and the options to cancel or allow. I hit allow and it just takes me into the account itself, at no point am I ever given any kind of verification code that I can put in to get the console working.
At this point I'm stuck and can't go any further so I'm activating the network. Any ideas as to where I'm going wrong?
Did you specify a redirect or callback url at any point in the oauth config process? It's probably done on tumblr's API website. This url would be your app's endpoint to which Tumblr sends a request to with the user's data. By the way, oauth can sometimes be confounding to set up. You won't be able to use localhost as a callback url, for example, though you can get a temporary domain name with a free local tunneling app.
edit To go into more detail on some of these points ...
callback url: To reiterate, this cannot be localhost. Setting the correct callback url will get you unstuck from your current predicament. Instead of redirecting to the tumblr homepage, you want the confirmation page to redirect to your app. Anyway, I think you're totally sensible to want to test it out before you deploy. But unless you deploy or use a local tunnel, your local application doesn't actually have a URL that can be reached from anywhere except your computer.
local tunnelling services: ngrok, localtunnel. To give an example with ngrok: Say you have a Rails server running on port 3000. Then in another terminal you run ngrok 3000 and you get a url which exposes your local server to the real internet. Note that this changes every time you restart ngrok (unless you pay them). In your application, you should make a unique route for the callback. Say you have a route which matches /oauth_callback to the oauth_callback controller action. Then the route you'd provide as your callback url would be http://MY_CUSTOM_NAME.ngrok.com/oauth_callback.
The controller action: I don't specifically know how Tumblr sends user data to the callback. Perhaps the information is in the headers or maybe it's in the body. It might be JSON or XML. Whatever it is, you can explore the data by placing a breakpoint in your controller action. You can inspect the params, headers, etc. I'd expect that they'd give you some token credentials and probably a user name/email as well.
i'm trying to create a web app with back and front end separated, so there is two project here. The reason is there is a plan in the future to create mobile version as well, so i made it decoupled.
Just FYI the back are created with PHP using laravel4 and barryvdh CORS
and the front end are created purely with angularjs and bootstrap.
The current situation is that i create a rest API in my back end app to do login, auth, and logout.and in the front end i have 2 pages, which is login and index page.
Login page are composed of username, password input field and submit button,
when user click submit button, it will call the login rest API from the back end and i expect it would persist cookie to the front end page if login success, but it doesn't (because of cross origin policy, i've research as much).
The question is, is there any way to set sessions across domains now it is 2014, where any article i found are from 2012 older. If it's not possible, what's the easiest way to persist session across domain besides OAUTH2 and openID (because their learning curve are just too steep, the application i'm creating are just small app)
Thanks for your assistance.
what I have done so far to work with cross-domain sessions is to create a "passport" service on a another domain and validate & handle the session from the there.
For example...
domain1.com has webserver1
domain2.com has webserver2
passport.com has webserver3
Whenever I connect either to domain1.com or domain2.com I'm including a line at the very top of the script index checking on passport.com/check.php whether there's a browser session already initialized under the name of "PASSPORT", if so, I finish the checking on passport.com and let the script on domain1.com or domain2.com to do their stuff.
In case the browser session wasn't initialized, the check.php will redirect the index via header() to the login.php page. This will validate against LDAP and if binding the user is OK then the browser session is initialized with the name of "PASSPORT" and including all the fields I need furthermore to validate the user and its accesses. Ref back to the index once is done.
When the user goes from domain1.com to domain2.com (or the other way around) the script included at the top of each index will check the session again all the time, taking the user to the login script or letting him access the required site.
As additional checking you can create the session and add variables such as "valid until", "access level", etc.
Hope this helps and if you need further clarification let me know.
Best,
Emiliano.
So, I have a web application that makes a lot of requests to the server for data. A project requirement is to have very fast server response times. The server is hosted on a cloud based platform.
The app uses sessions to keep track of user authentication once they've logged in. Since it's hosted on a cloud provider, I'm using a cache to back up session storage (in my case it's Auzre cache, but if you're unfamiliar with that think Redis)
The current flow is like this:
The user accesses a resource
Trying to get the session based on the session ID via the cache. This is a cache request.
User is authenticated via session state (if logged in).
Request for data is sent, usually via cache.
Data is returned to the user.
The problem with this approach is that it's hitting the cache twice. Removing the session altogether caused a significant speed improvement (about 50%).
I was considering hitting the cache once, asking for both the key I need for the user, and the SessionID to save the extra round trip. However, I've never seen this approach before, and it requires 'rolling my own session' as I'd have to generate the session IDs and such. I feel like there might be a simpler, easier way.
So, what would be the most efficient way to serve the user a resource and authenticate them?
Note: I'm using ASP.NET MVC/ WebAPI with C# but I don't find that very relevant to the question, so I left the language and platform out of the question because of it.
You would want to combine the authenticate and resource request steps into one single request. Not only is this faster, it is also safer than your implementation. Consider the following scenario:
User authenticate to the server. Result is success.
Authentication is changed. (e.g. user changes password, admin decides to lock the user account, etc.)
User makes a request using the sessionID in step 1.
To ensure that the user is not granted access to the resource, you'd want to authenticate the user precisely at step 3. But that doesn't make sense, you've already authenticated this user previously in step 1...
HTTP, in is core, is designed exactly to do this. There are various ways to pass authentication information along with the request, such as:
Write the authentication information in the content (stupid, but works)
Include authentication in the url, e.g. example.com/pic/123?sessionID=abc (better, but makes your url ugly and long)
Store session info in cookie (better, but what if the client does not support cookie? what about cookie expiration?)
Authenticate HTTP header (my best personal recommendation)
HTTP itself has an authenticate header meant to be compatible with "basic authentication" (it is well defined, look it up if you're interested). But you can implement your own custom header.
Any cache lookup is bound to be slow (compared to computation), so you should omit the cache for the authentication part all together. Your server should be stateless; i.e. do not keep track of login sessions. How do you know if the sessionID is valid? Put a timestamp on it. And to avoid others faking the sessionID, sign it as well.
So, your HTTP request would look something like this (pseudo code):
var request = new HttpRequest();
request.url = "example.com/pic/123";
request.Headers["CustomAuth"] = "id=abc&t=123456789&s=01de45890a";
Implement your own signing method, sort of like a hash function (you can use HMAC), and keep the key securely on the server. If the signature matches, you know you've signed this previously at the login, and it has to be from your server. A timestamp helps you detect session expiration and also protect against replay attacks.
Now in your server, do something like this:
public void Get(){
var authHeader = Request.Headers["CustomAuth"];
if(!validate(authHeader)){
Response.StatusCode = 404;
Response.End();
}else{
//something else
}
}
If you need to do login + session authenticate + resource request in one request, then there're simply just 2 ways for authentication. Users can either provide a username/password combination, or a session key. Think about this scenario, which comes from an API I worked on:
user register with username/password combo
server responds registration success / failure (e.g. username already taken)
if it was a success, user now logins with username/password combo
server returns a session token
Wouldn't it be simpler (and faster) if we do it this way:
user register with username/password combo
if it is success, respond "reg success" and "sessionToken=xxxxxx". if it is failure, respond "reg failure".
I hope this give you some idea.
Also, you can remove the authentication at the server end by modifying / restricting settings on the server to cater to requests coming only from the ip(s) where your web app is hosted. Your web application will let the request pass to server only if its authenticated and hence all the requests reaching the data server will be served automatically without checking for any authentication. In this case you will just need one cache hit to check if the user is authenticated and straight away hit the server.
I have this web app written in AngularJs that uses cookies to authenticate the requests in a REST API.
Once the user logs in, the cookie is received and saved in the browser and all subsequent requests send the cookie along to the server. There is a 'User' service/object that saves the isLoggedIn and username values (for UI display/flow). Now, if I refresh the 'index' page, the app restarts. This means that my 'User' object will be cleared. I can check the existence of the cookie and, if it exists, I can re-set the User.isLoggeIn as true and go from there, but I still need to get the username, id, etc. So, my question is: should I create some sort of 'ping' endpoint in the API to verify if a cookie is valid? And if so, the API would send me back the user id and username... OR should I persist the user data in LocalStorage (or some similar cross-browser thing) and just assume the user is logged if the cookie exists? Any other subsequent requests to pages that need authentication would be automatically verified. So, this question really only applies to the scenario where the user refreshes the index page - hence, restarting the web app. I want to know the user data because I want to show a 'user homepage' instead of the 'public homepage'.
What do you think?
You should depend on the server for this. Creating something like GetCurrentUser method on the server. If the user is logged on this returns all the properties of the user.
You should even use this server api to get the user data after authentication completes. So the authentication become two step process first the user is authenticated, on success another call is made to server to get current users details.
Using client side local storage for this would not be ideal because you need to do lot of book keeping, in terms of cleaning the logged in user on log out or session expiration.
Also cookies from server would have expiration times an all, and making decision just based on cookie existing on local storage may not be optimal approach.
I want to use post to update a database and don't want people doing it manually, i.e., it should only be possible through AJAX in a client. Is there some well known cryptographic trick to use in this scenario?
Say I'm issuing a GET request to insert a new user into my database at site.com/adduser/<userid>. Someone could overpopulate my database by issuing fake requests.
There is no way to avoid forged requests in this case, as the client browser already has everything necessary to make the request; it is only a matter of some debugging for a malicious user to figure out how to make arbitrary requests to your backend, and probably even using your own code to make it easier. You don't need "cryptographic tricks", you need only obfuscation, and that will only make forging a bit inconvenient, but still not impossible.
It can be achieved.
Whenever you render a page which is supposed to make such request. Generate a random token and store it in session (for authenticated user) or database (in case this request is publicly allowed).
and instead of calling site.com/adduser/<userid> call site.com/adduser/<userid>/<token>
whenever you receive such request if the token is valid or not (from session or database)
In case token is correct, process the request and remove used token from session / db
In case token is incorrect, reject the request.
I don't really need to restrict access to the server (although that would be great), I'm looking for a cryptographic trick that would allow the server to know when things are coming from the app and not forged by the user using a sniffed token.
You cannot do this. It's almost one of the fundamental problems with client/server applications. Here's why it doesn't work: Say you had a way for your client app to authenticate itself to the server - whether it's a secret password or some other method. The information that the app needs is necessarily accessible to the app (the password is hidden in there somewhere, or whatever). But because it runs on the user's computer, that means they also have access to this information: All they need is to look at the source, or the binary, or the network traffic between your app and the server, and eventually they will figure out the mechanism by which your app authenticates, and replicate it. Maybe they'll even copy it. Maybe they'll write a clever hack to make your app do the heavy lifting (You can always just send fake user input to the app). But no matter how, they've got all the information required, and there is no way to stop them from having it that wouldn't also stop your app from having it.
Prevent Direct Access To File Called By ajax Function seems to address the question.
You can (among other solutions, I'm sure)...
use session management (log in to create a session);
send a unique key to the client which needs to be returned before it expires (can't
be re-used, and can't be stored for use later on);
and/or set headers as in the linked answer.
But anything can be spoofed if people try hard enough. The only completely secure system is one which no-one can access at all.
This is the same problem as CSRF - and the solution is the same: use a token in the AJAX request which you've perviously stored eslewhere (or can regenerate, e.g. by encrypting the parameters using the sessin id as a key). Chriss Shiflett has some sensible notes on this, and there's an OWASP project for detecting CSRF with PHP
This is some authorization issue: only authorized requests should result in the creation of a new user. So when receiving such a request, your sever needs to check whether it’s from a client that is authorized to create new users.
Now the main issue is how to decide what request is authorized. In most cases, this is done via user roles and/or some ticketing system. With user roles, you’ll have additional problems to solve like user identification and user authentication. But if that is already solved, you can easily map the users onto roles like Alice is an admin and Bob is a regular user and only admins are authorized to create new users.
It works like any other web page: login authentication, check the referrer.
The solution is adding the bold line to ajax requests. Also you should look to basic authentication, this will not be the only protector. You can catch the incomes with these code from your ajax page
Ajax Call
function callit()
{
if(window.XMLHttpRequest){xmlhttp=new XMLHttpRequest();}else{xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}
xmlhttp.onreadystatechange=function(){if(xmlhttp.readyState==4&&xmlhttp.status==200){document.getElementById('alp').innerHTML=xmlhttp.responseText;}}
xmlhttp.open("get", "call.asp", true);
**xmlhttp.setRequestHeader("X-Requested-With","XMLHttpRequest");**
xmlhttp.send();
}
PHP/ASP Requested Page Answer
ASP
If Request.ServerVariables("HTTP_X-Requested-With") = "XMLHttpRequest" Then
'Do stuff
Else
'Kill it
End If
PHP
if( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && ( $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' ) )
{
//Do stuff
} else {
//Kill it
}