Shopify Rails App - Querystring Spoofing - ruby-on-rails

I'm developing a Shopify App with Rails and have been using the query-string to detect which shop is accessing it. This seems vulnerable as users could alter the url to access someone else's settings.
Here's an example:
I click on the preferences link on my app and get redirect to http://example-app.com/preferences?shop=example.myshopify.com and get a page of settings related to the the store: example.myshopify.com
So what's to stop the user from changing the querystring to http://example-app.com/preferences?shop=notmystore.myshopify.com and logging in to a store that they don't own?
Should I use an authentication gem (https://www.ruby-toolbox.com/categories/rails_authentication) and make each user create a username and password to prevent spoofing attacks?

Interesting. There were live production Shopify App store Apps that did what you did Paul. When I found an App like that, I informed Shopify and they promptly knuckle wrapped the App developer. He learned his lesson pretty quick and was hopefully very embarrassed.
Shopify Partner accounts (free to get) provide you with a nice API token and a corresponding secret for your App that you can use to ensure when you get a merchant trying to access your App that the incoming shop
is actually a shop that installed your App and,
they have the right to use your App
You should really check that out.

I found the solution is to always retrieve the shop url from your session variables and not from the query string:
session[:shopify].url
also make sure this is at the top of each of your controllers to ensure the shopify session exists:
around_filter :shopify_session
as shown in this: https://github.com/Shopify/shopify_app/blob/f9aca7dfc9c29350f7f2c01bb72f77a54ece2b77/lib/generators/shopify_app/templates/app/controllers/home_controller.rb

This question may be too localized, but I'll try to give you a direction.
If you are using the query string as the only authentication method, then yes, you will get hacked/spoofed, etc. You need to do some form of authentication. - Shopify provides an API that can probably handle some/most of this for you.
https://github.com/shopify/shopify_api

Related

How to use Stripe Connect in an iOS app

Has anyone had success using Stripe connect with an iOS app. I have a few questions:
I'm following the guidelines here: https://stripe.com/docs/connect/getting-started
Registering an Application: easy, no problem here
Then a little further down:
Send your users to Stripe: again, easy no problem here, I just have a button that opens up the link in a UIWebView. I assume having the client_id in the URL is fine? A lot of my uncertainty is what IDs/keys I should hard-code into the app
Then a little further down:
After the user connects or creates a Stripe account, we'll redirect them back to the redirect_uri you set in yourapplication settings with a code parameter or an error.
What I'm doing here is using the UIWebview's webView:shouldStartLoadWithReqest:navigationType delegate method to check for the string "code=" in the URL. If it finds that, then I'm able to grab the "code" parameter. So in reality, the redirect_uri is completely unnecessary for me. Is this the right way to handle this? Should I be doing this within my app or on my server?
After receiving the code, we are supposed to make a POST call to receive an access_token. Again, should this be done within the app or on the Server? It requires the use of a secret_key, so I'm guessing server? And how do I send credit card information along with this token if the token needs to be sent to the server? I know how to obtain the card number, exp date, and CVV. But in terms of passing it to the server (with or without the token) is something I'm not sure of.
Then when it comes to actually writing PHP, Ruby, or Python code on the server, I'm at a total loss.
Any help would be greatly appreciated.
You should setup a small web app to create stripe charges and storing you customers Authorization Code. Configure two routes in your web app for redirect_uri and webhook_uri and add the url in your Stripe Apps settings. The charges should be created from a server side app because it requires the secret_key / authorization_code which should not be stored in an iPad app. Otherwise they may lead to a security leak. I'm trying to describe the concept below:
Provide the stripe connect button in your app and set the link to open in Safari (not in an web view). You should add a state parameter to the url with an id which is unique to your users.
On tapping the button your user will be redirected to Stripe where s/he will be asked to authorize your application. Upon authorization stripe will hit your redirect_uri with a authorization_code and the state you previously provided. Do a post call according to Stripe Documentation with the authorization_code to get an access_token. Store the access_token mapped with the state in a database.
Define a custom url scheme in your app. Invoke the custom url from your web app. The user supposed to open the url in mobile safari. So invoking the custom url will reopen your application. You can pass an additional parameter to indicate failure / success. In your app update the view based on this parameter.
Now you are all set to create a charge on your server on behalf of the iPad user. Use stripe iOS sdk to generate a card_token from the card information. It'll require your stripe publishable_key. Then define an api in your web app which takes 3 parameters: card_token, user_id and amount. Call this api from your iPad app whenever you want to create a charge. You can also encrypt this information with a key if you're worried about security using any standard encryption method. You can easily decrypt the info in your web app as you know the key.
When this api is called from the iPad app you'll receive the user_id (which you saved as state previously), card_token and amount. Retrieve the access_token mapped to the user_id (or state). You can then made a charge on behalf of the user using the access_token, card_token and amount.
You can use ruby / php / python / node in the server as Stripe provides sdk for them. I assume other languages can be used as well as there is a REST interface.
Please note that this is just a concept. It should work like it but I haven't implemented it yet. I'll update this answer with sample code when I'm done.
You can use UIWebView. You will still need to use redirect urls and monitor the redirect using the delegate "webView:shouldStartLoadWithRequest:navigationType:"

Protect server URL in mobile app

I know this can sound absolutely stupid, but I could not find any way to solve this problem.
Say I've a mobile app: from this app, after purchasing an item, since the item is downloadable from a server, I make the user download a file to his device. Problem is it looks like it is very easy even for not so smart people, to get the URL of the file, so, without purchasing anything, the not-so-smart-guy can eventually download the same file for free (using a common browser).
Apart from the language I use (it is not important here, it can be JavaScript, Java, Objective-C, whatever), how can I prevent this issue WITHOUT developing an authentication system?
Generate a token for successful purchase, store it in the server side session or database. Add the token as a query string parameter for the file download request. Implement an filter for the file download request to validate the token.
To make sure that the URL is not share able - find some unique attribute of the device that can't be spoofed easily, hash(url,token,unique property) and add it to the url.

Smartphone login with device

To my understanding creating a smartphone apps based on a site is to simply create an API for the website and to output the data in XML, JSON. In my case JSON has Ruby on Rails has it built it in it. In theory all I have to is to read the event.json page and read the attribute and on phonegap to read it and build a logic from it.
However, in my phone app, I would like to allow user to log in before entering and in fact on the web-base I am using the devise gem to manage my user management. How am I supposed to allow user to log in from device using phonegap? Should I read an API JSON that showcase all users but then that may cause a lots of security issues, is there a device documentation on that specific issue, or should I scrap device and just make an authentication system from scratch?
Devise provides for an auth-token to be used for login. This works well with JSON APIs as you can set a header to include the auth-token to identify the user. Your login form would just be responsible for getting an auth-token from valid credentials. SSL can help to secure this information on the wire.
I created a Gem based on rack_iphone which store the session
in the localStorage and and upon opening a application from a home screen shortcut
the application take the cookie if present from the localStorage and the sent it to the server
Hope this work for you

Soundcloud OAuth2 API: Getting invalid_scope error after user connection

I'm trying to implement Soundcloud connect and having a weird issue.
First thing I do is send my users to
https://soundcloud.com/connect?client_id=MY_CLIENT_ID&redirect_uri=http://myredirecturl.example.com&state=RANDOM_STRING&display=page&response_type=code&scope=email
When users connect they get redirected to
http://myredirecturl.example.com?error=invalid_scope&error_description=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed.&state=RANDOM_STRING
The same happens if I use scope=*.
However, if I use scope=non-expiring it lets me go through, but I need the users email and that type of scope doesn't have enough grants.
I thought it had something to do with my app being in development mode, but Osman at Soundcloud said it doesn't.
Thanks.
The 'email' scope is not available to all integrations. It's used for a few custom integrations that have provided us with accepted terms of service / privacy policies. There is no way to get a user's email address using the SoundCloud API.
You should however be able to use the '*' scope to get an expiring access token. I'll check with our app team to see why this is giving you an error. I'll edit my answer once I have more information there.
For your purposes, I would stay with the 'non-expiring' scope and simply prompt a user for their email address (providing them with a way to agree to your terms of use / privacy information).
Using scope=* sometimes doesn't work because the url is not properly encoded. If you are getting this error while using the * wildcard, try properly encoding the url, using a function like urlencode() (for PHP).

Rails 3 and iOS Architecture Review

My goal is to build a standalone RESTful Rails 3 service that communicates with a Rails 3 web application via ActiveResource JSON and an iPhone application via iOS 5 native JSON. I have each running so that a single table of data is being exposed in the service app and that can be called and rendered via both a Rails app and the iPhone app.
My question is around authentication and something that can be reusable for both the web application and the iPhone app or in the future an Android app.
From the research I have done on this site, it seems HTTP Basic would work for both, however I would be unable to properly logout a user on the web side like sessions or cookies could and I have the browser login form to deal with. If I use sessions, how would that translate to setting up authentication on the iOS side of things?
This project is a code learning exercise, so I am hoping for implementation or architectural guidance rather than simply implementing Devise or Authlogic, etc.
It sounds like you're conflating at least two problems.
The first issue is authentication: you need to determine if the user is who they say they are. For authentication, you can do basic auth. You could also use client certs, though that's probably not what you're looking for.
The second thing is session management: First, you can do basic auth on each page request and store the session state in the database, but you're right about not being able to log the user out, as the browser will cache the credentials.
You may want to consider a login page that requires basic auth and shoots back a cookie to do session management. All other pages don't require basic auth, but give a 401 unauthorized if the cookie isn're present. Or you could redirect. The iOS client code will have to know to call the login page first to get the cookie and then use it after that. Logging out is deleting the cookie.. hrmm, but the browser will still cache the basic auth credentials.
I'm thinking the only way you're going to get what you want is to have a form-based auth for your web users (to allow them to log out and log in as someone else), and a basic-auth based system for iOS users. As a result of both authentication mechanisms, return a cookie that has to be used for all other pages.

Resources