Posting data between Rails app - ruby-on-rails

Ok so here's the big picture, I have 2 sites, call them SiteA and SiteB. SiteA sort of serves as a master site when it comes to ecommerce transactions (We only have one account with our Credit card processing company, so successful/declined transactions get redirected to SiteA)
So a user logs on to SiteB, goes through the buying process and submits the form with the credit card details which gets posted to the credit card verifying company, upon a successful transaction SiteA receives all the necessary info (in a POST method) sent by the Credit card processing company. At this point the code on SiteA, based on a param determines which site the transaction originated and again POSTS the data to that site using this code
Net::HTTP.post_form(URI.parse("http://#{params[:site_name]}/success"), params)
success is defined in routes.rb as
map.connect 'success', :controller => "some_controller", :action => "success"
The problem however is that although the user is logged in on SiteB, when SiteB receives the data POSTed by SiteA (which obviously doesn't know anything about SiteB's session_id), further processing of the data on SiteB fails due to lack of session information.
Both the sites are running exactly identical code.
My question, is there a way where in session data from SiteB can be requested and appended to the Post data when SiteA sends the data.
Many thanks

If these two sites are running on the same physical machine, you can always use something like Memcache as a simple way to exchange state information between two otherwise unrelated sites. If they are on separate machines, using a POST may be your only reasonable option though it ends up being more of a hassle to implement.
If SiteB must forward to SiteA for some processing, and SiteA needs to return the visitor back to SiteB, you need to create a private API on both applications. You can usually get by with creating a simple REST interface and dumping whatever you need in a simple serialized format such as YAML or JSON depending on your preference.
For instance, the procedure might be roughly as follows:
Visitor is forwarded from SiteB to SiteA via a HTTP redirect.
Visitor proceeds with transaction on SiteA and a record with a unique identifier is created in the database that reflects the outcome of this transaction.
SiteA forwards the visitor back to SiteB with this unique identifier as a parameter.
SiteB makes a request to SiteA to retrieve the details of this transaction.
SiteB updates its internal records as required and presents the outcome of the transaction to the visitor.
To be secure you should probably generate random unique identifiers, as something like UUID will prevent people from inspecting arbitrary orders by guessing numbers. You should also ensure that the call to SiteA to retrieve transaction details has some kind of access control even if it is only a secret token or passphrase. A more robust implementation would probably use TLS and SSL certificates to verify the origin of any request.

Related

Forging a Cross Site Request Forgery (CSRF) token

I had a look at Rails' ActionController::RequestForgeryProtection module and couldn't find anything related to using secrets. Basically, it uses secure PRNG as a one time pad, xors, computes Base64 and embeds into HTML (form, tags). I agree that it is impossible for an attacker to guess what a PRNG generates, but nevertheless I can generate (or forge if you like) a similar token, embed it into my "evil" form and submit. As far as understand Rails compares ( verifies) it on the backend. But I can't fully understand why it is secure. After all, I can generate my own token exactly like Rails does. Could someone clarify how the security is achieved?
You might misunderstand what this protects against, so let's first clarify what CSRF is, and what it is not. Sorry if this is not the point of confusion, might still be helpful for others, and we will get to the point afterwards.
Let's say you have an application that allows you to say transfer money with a POST request (do something that "changes state"), and uses cookie-based sessions. (Note that this is not the only case csrf might be possible, but by far the most common.) This application receives the request and performs the action. As an attacker, I can set up another application on a different domain, and get a user to visit my rogue application. It does not even have to look similar to the real one, it can be completely different, just having a user visit my rogue domain is enough. I as the attacker can then send a post to the victim application's domain, to the exact url with all the necessary parameters so that money gets transferred (the action will be performed). The victim user need not even know if this happens in xhr from javascript - or I can just properly post a form, the user gets redirected, but the harm is done.
This is affected by a few things, but the point is that cross-origin requests are not prevented by the same origin policy, only the response will not be available to the other domain - but in this case when server state changes in the victim application (like money gets transferred), the attacker might not care much about the response itself. All this needs is that the victim user that visits the attacker's page while still being logged in to the victim application. Cookies will be sent with the request regardless of the page the request is sent from, the only thing that counts is the destination domain (well, unless samesite is set for the cookie, but that's a different story).
Ok, so how does Rails (and similar synchronizer token solutions) prevent this? If you lok at lines 318 and 322 in the source, the token received from the user is compared to the one already stored in the session. When a user logs in, a random token is generated and stored for that particular user, for that particular session. Subsequent requests that change state (everything apart from GET) check if the token received from the client is the same that's stored in the session. If you (or an attcker) generate and send a new one, that will be different and the request will fail validation. An attacker on their own website cannot guess the correct token to send, so the attack above becomes impossible. An attacker on a different origin also cannot read the token of a user, because that is prevented by the same origin policy (the attacker can send a GET request to the victim app, but cannot read the response).
So to clarify, CSRF is not a protection against parameter tampering, which might have caused your confusion. In your own requests, if you know the token, you can change the request in any way, send any parameter, the CSRF token does not protect against this. It is against the attack outlined above.
Note that the description above is only scratching the surface, there is a lot of depth to CSRF protection, and Rails too does a little more, with some other frameworks doing a lot more to protect against less likely attacks.

Filtering route parameters

So I have a route in routes.rb like:
get "example/:token" => "example#example"
and even though I have config.filter_parameters += [:token] in production.rb, I still get a log output like:
Started GET "/example/fjiaowevnieninr3"
Parameters: {"token"=>"[FILTERED]"}
where as you can see "token" is filtered in the Parameters, but still appears in the URL path. I'd always assumed filtered_parameters would filter it there as well but I guess not. Is there an official way to filter out named route parameters like this from the logs?
In general it depends on why do you need this kind of behaviour. allenbrkn answer is correct you can send it through query string and it will be filtered from the query string. That said there are more things to consider when you are trying to do this.
There are more type of logs
In the production environment you use some webserver like Apache or Nginx, they have their own access logs, in which they log some headers, paths with query strings and so on (it is configurable).
It means that even if you filter out URL token from the rails log, they will probably appear in the webserver access logs.
Also don't forget these parameters can be sent to external services eg. exception tracking or performance tracking softwares.
Things in the URL are public
Tokens in the URL should not be considered as a secret. Your user can see them manipulate them, send the url to anyone or randomly show it to someone.
I think there two main reasons to put the token into the URL
Hard to guess URL
User authorisation
Hard to guess URL
In this case token is always the same. It is not changed with every access of the URL. It can be usually used as an ID of some resource or something.
For example we are using it as public URLs for invoices so we can send just a link to our clients and they can download the PDF from our site and there are some things to help them with the payments. In the URL is some token so they cannot guess the URL and access invoices of other clients. The token is always the same, so they can access the invoice from the email several times. And the URL is still in the rails log and server access log and we are fine with it because we know the tokens anyway - they are part of the invoice ID.
In these cases it also helps you with the debugging. If some exception kicks in or if there is some issue with the resource it will be really hard to find out why.
User authorisation
This is a bit more complicated. When it comes to authorisation you shouldn't put your tokens into the URL. They should always be in the body and filtered out of the log or in the authorisation headers. Unfortunately sometimes you don't have much of a choice if you need to use it during the GET requests eg:
Single sign on (redirect flow)
Password reset
etc
(Of course you can use request body even with GET requests but you are risking to loose the data eg if the user puts in the URL manually etc)
In these cases you should make possible exposition to valid tokens as short as you can:
Always issue new token on demand never reuse same tokens
Work with very short expiration times
Every token should be invalidated immediately after its use
With these rules it should not matter whether they appear in the logs or not.
For example we have single sign on implemented in our application. The valid token is issued only on demand with 1 minute expiration time and it is invalidated immediately when it is used. In this case it can appear in the log because at the time of appearance it is already invalid and useless.
With password reset it can be a bit more complicated you need token to be valid at least tens of minutes probably and it will appear in the log before it is invalidated. But there are probably not too many things you can do about it - btw if someone has some good ideas I will be very happy to read it.
Conclusion
You can filter the tokens from rails logs but they still probably appear in other logs or even other services if you use them. You should work with your tokens in the URL as if they can appear there and make it as safe as possible for you if they do. Rails log is just one piece of puzzle you have to consider.
As far I know, there is no in-built way of filtering the URL like GET /example/[FILTERED]. But you can create your own method to do that.
After a little examining of https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/filter_parameters.rb file, I found that filtering params will also filter the query_string of the path.
For example: In your case above, if you make a request to /example/fjiaowevnieninr3?token=fjiaowevnieninr3, the result in logs would be:
Started GET "/example/fjiaowevnieninr3?token=[FILTERED]"
Parameters: {"token"=>"[FILTERED]"}
So I would suggest you to send your token as a query parameter and do something like this:
In your routes add:
get "example/auth" => "example#example"
Then you can make a request like /example/auth?token=123456
You can catch this token in controller with params[:token]
This way your logs will show:
Started GET "/example/auth?token=[FILTERED]"
Parameters: {"token"=>"[FILTERED]"}
Also, config.filter_parameters is moved from config/application.rb to it's own file at config/initializers/filter_parameter_logging.rb file.
Add the token symbol to your config/initializers/filter_parameter_logging.rb:
Rails.application.config.filter_parameters += [:password, :token]
Also, don't forget to restart the server.

Track anonymous users without forcing users to go through authentication proccess

I want to track all users (both authenticated users and anonymous users) , so far the solution i found are not good.
First of all, we can use a cookie but as we all know its not a reliable solution, second of all we, can use browser finger printing, but until this moment I did not find any solution for server side.
I found this solution valve but it is for client side and this one browserFingerPrint , I want an approach which user does not find any token in request , I want to create the key in server side so I can track users.
Does any one know any solution?
note : my server side technology is Asp.net Mvc
use case : users can comment on m site and also they can like or dislike comments, I want to allow all users to do this and also I want to track users before action (like or dislike)
No, there is no solution for what you want that doesn't use some form of a "token" which fingerprints anonymous users.
Let's see why.
An anonymous browser sends a series of bits of data, such as IP, browser agent and other headers. These should never be used to identify a user because they can be easily forged. They can be OK for tracking, and for most purposes IP address or some hash based on IP address and browser agent is sufficient. However this won't do for things which require security, such as commenter identification.
For commenter identification, it is necessary to prevent fraud. This is typically achieved by giving a unique token to each user. This can be transmitted in many forms, off the top of my head: cookies, headers, query string, POST parameters, or client certificates. However it does require a token issued by the server. If the client can generate a token from scratch, then it follows it can generate a fake token.

Cross site session creation with Devise

I'm working on a project that uses sessions to manage the currently logged in user with a slight twist, there is no log in form on the actual application. Instead, another site will provide a button that should log in the user and redirect to their profile page.
For example, the customer is viewing their profile on Site A, the 3rd party application. From their profile on Site A they click on a button that should log them in to Site B and redirect to their profile on Site B, the site I'm building.
I'm a unfamiliar with the security concerns for a case like this. My initial thought is that if Site A POSTs via https the user's email address and password, then it should work just as if they were filling the form out on my site, Site B.
What security concerns am I missing here or will this just not work at all?
NOTE: The 3rd party site is basically out of my hands and I'll never convince that team to setup any sort of OAuth protocol, or at the very least its going to take unacceptably long. Plus, OAuth, at least with my understanding is method to accept requests from any number of 3rd parties. No other site except for SiteA will ever attempt to log people in.
This sounds like a typical application for an OAuth provider.
Get an overview and grasp the concept here: http://en.wikipedia.org/wiki/Oauth
There already exists OAuth Providers in Ruby, so you don't have to do everything by yourself: e.g. https://github.com/songkick/oauth2-provider.
But if you really wanna do this without, then I would let the other server generate a hash containing the users id (can be username, email, or database id), a random token, the current timestamp and then sign this using MessageVerifier. Then you can check on your server if the timestamp is within a certain range (some minutes) and if the message verifies (using the same key naturally). If so, then accept the user.
If the other site uses PHP, then you might have to rebuild the generate method in PHP. Find the source in Ruby here.

Opening up part of a secured application without compromising the entire application

There's a subset of users which will not have access to the system I'm implementing in the beginning but I need a mechanism for them to capture data for one specific part of the process.
An authorized user creates the original record for a Person with some basic details i.e. First name, last name etc.
I then create a 'DataRequest' record which has a unique guid and the external user is sent an email with a path which is effectively http://sampleapplication/Person/Complete?guid=xxxx
The external user adds additional details like Date of Birth, Eye colour etc, submits and saves to the DB. The DataRequest for that guid is then expired and cannot be accessed again.
The Complete action doesn't have any authorization as these external users do not have user accounts.
My preference is to force these users to use the system but at this stage I'm not sure it's practical.
Is this a bad practice?
Should I be implementing some additional security on this like a one time password / passcode contained in the email? Are there alternative approaches I should consider?
There's nothing wrong with opening up a section of your site to the public. Tons of websites have secured and unsecured sections. However, there's also nothing saying that you have to expose your secure site at all. You can create another site that merely has access to that change those records and make that site alone, public.
As far as securing the information of the user, passcodes by email are the invention of some developer somewhere with limited mental ability or a severe lack of sleep. If the link is only available by email (not discoverable by search engines and not easily guessable), then anyone with the link will also have the passcode, making the passcode to access the link redundant.
You should however log when the email is used to finish the record and then disallow further uses.

Resources