Creating proxy pages with rails without cookies and session id

807 views
Skip to first unread message

Gerwin Brunner

unread,
Feb 8, 2012, 12:29:54 PM2/8/12
to shopi...@googlegroups.com
Hi,

I started to create a shopify proxy app to build a customer signup form where we can collect the company name and also some additional values like VAT number.

It works fine, for the validation of forms, which is great.

But  everything that uses the session (like flash notices) does not work.
Would it be possible to pass the shopify session thru to the proxy. That way we should be able to work around this topic.

I would also love to have the information if the customer is logged in to give him access to pages that only he should have access to.

Mit freundlichen Grüßen
Gerwin Brunner

---------------------------------------
---------------------------------------
Bizzons eMarketing GmbH
Nikolaiplatz 4
A-8020 Graz
---------------------------------------
Firmenbuch: FN 269991x
Handelsgericht Graz
---------------------------------------







Dylan Smith

unread,
Feb 8, 2012, 5:44:22 PM2/8/12
to shopi...@googlegroups.com
On Wed, Feb 8, 2012 at 12:29 PM, Gerwin Brunner <gerwin....@bizzons.com> wrote:
I started to create a shopify proxy app to build a customer signup form where we can collect the company name and also some additional values like VAT number.

It works fine, for the validation of forms, which is great.

But  everything that uses the session (like flash notices) does not work.
Would it be possible to pass the shopify session thru to the proxy. That way we should be able to work around this topic.

The api proxy is working as documented:

Cookies are not supported for the application proxy, since the application is accessed through the shop’s domain. Shopify will strip the Cookie header from the request and Set-Cookie from the response.

The problem is that the proxy application is running in the shop's domain.  Without this protection your application would be reading and writing cookies that are used by Shopify itself, along with any other proxy applications installed in the application.  So this was done for security and reliability.
 
I would also love to have the information if the customer is logged in to give him access to pages that only he should have access to.

You could put conditional logic around the content that is only for customers in a liquid response.  Liquid could also be used to store customer information in fields, which could be used as parameters to other requests (e.g. AJAX requests).

Sorry for not having an ideal solution for your problem at the moment.  The main use case for the API proxy is for the storefront, i.e. public content.

G B

unread,
Feb 9, 2012, 8:42:30 AM2/9/12
to shopify-api
Hi Dylan,

thanks for your answer.

On Feb 8, 11:44 pm, Dylan Smith <dylan.sm...@jadedpixel.com> wrote:
> On Wed, Feb 8, 2012 at 12:29 PM, Gerwin Brunner
> <gerwin.brun...@bizzons.com>wrote:
>
> > I started to create a shopify proxy app to build a customer signup form
> > where we can collect the company name and also some additional values like
> > VAT number.
>
> > It works fine, for the validation of forms, which is great.
>
> > But  everything that uses the session (like flash notices) does not work.
> > Would it be possible to pass the shopify session thru to the proxy. That
> > way we should be able to work around this topic.
>
> The api proxy is working as documented:
>
> From api.shopify.com/app_proxy.html
>
> > Cookies are not supported for the application proxy, since the application
> > is accessed through the shop’s domain. Shopify will strip the Cookie header
> > from the request and Set-Cookie from the response.
>
> The problem is that the proxy application is running in the shop's domain.
>  Without this protection your application would be reading and writing
> cookies that are used by Shopify itself, along with any other proxy
> applications installed in the application.  So this was done for security
> and reliability.

That makes total sense to me.
Would it be possible to add the following parameters ti the forwarded
request:
- session_id : we could use that in an rails app to keep track who
the user is and if to display the flash message -- kind of workaround
for the cookie issue -- and I think this would not compromise security
on shopify side. right?
- user_id / or user_email : only sent if the customer is logged in..
with this information I would be able to know what data I need to look
up in external datasources for this customer, do some processing and
then displaying it.
This would not be possible to be done only in the liquid, cause then I
would have to put all the customer data into that response and then
decide in the liquid which customer I want to be displayed... This
would be to huge with a lot of customers

Dylan Smith

unread,
Feb 9, 2012, 10:55:29 AM2/9/12
to shopi...@googlegroups.com
On Thu, Feb 9, 2012 at 8:42 AM, G B <gerwin....@bizzons.com> wrote:
Would it be possible to add the following parameters ti the forwarded
request:
 - session_id : we could use that in an rails app to keep track who
the user is and if to display the flash message -- kind of workaround
for the cookie issue -- and I think this would not compromise security
on shopify side. right?

Passing the session_id through in any form would still be a security issue.  We don't want it to be possible for an application to impersonate a customer in requests to shopify.  However, I believe you just need any unique read-only session id that stays consistent through through the browser session, which you could associate with writable session data stored on your applications datastore.

 - user_id / or user_email : only sent if the customer is logged in..
with this information I would be able to know what data I need to look
up in external datasources for this customer, do some processing and
then displaying it.
This would not be possible to be done only in the liquid, cause then I
would have to put all the customer data into that response and then
decide in the liquid which customer I want to be displayed... This
would be to huge with a lot of customers

If we do implement this feature, it would likely be the customer_id that would be provided.  This could then be used to lookup more customer data using the Customer API (http://api.shopify.com/customer.html).

I will record both of these as feature requests, but unfortunately I don't have any timeline on when they will get implemented.

G B

unread,
Feb 10, 2012, 7:57:39 AM2/10/12
to shopify-api


On Feb 9, 4:55 pm, Dylan Smith <dylan.sm...@jadedpixel.com> wrote:
> On Thu, Feb 9, 2012 at 8:42 AM, G B <gerwin.brun...@bizzons.com> wrote:
> > Would it be possible to add the following parameters ti the forwarded
> > request:
> >  - session_id : we could use that in an rails app to keep track who
> > the user is and if to display the flash message -- kind of workaround
> > for the cookie issue -- and I think this would not compromise security
> > on shopify side. right?
>
> Passing the session_id through in any form would still be a security issue.
>  We don't want it to be possible for an application to impersonate a
> customer in requests to shopify.  However, I believe you just need any
> unique read-only session id that stays consistent through through the
> browser session, which you could associate with writable session data
> stored on your applications datastore.

Yes that's totally true... I was not thinking of being able to fake
the user with the session info...
The unique session id would totally do the job. :)


>  - user_id / or user_email : only sent if the customer is logged in..
>
> > with this information I would be able to know what data I need to look
> > up in external datasources for this customer, do some processing and
> > then displaying it.
> > This would not be possible to be done only in the liquid, cause then I
> > would have to put all the customer data into that response and then
> > decide in the liquid which customer I want to be displayed... This
> > would be to huge with a lot of customers
>
> If we do implement this feature, it would likely be the customer_id that
> would be provided.  This could then be used to lookup more customer data
> using the Customer API (http://api.shopify.com/customer.html).

Yeah, that would make sense.
customer_id would do the job.

> I will record both of these as feature requests,
Thanks a lot!

> but unfortunately I don't have any timeline on when they will get implemented.
I'll be eager to test it out. So just let me know when I can


Thanks for your help!
Gerwin

mrkschan

unread,
Sep 5, 2012, 12:59:27 AM9/5/12
to shopify-a...@googlegroups.com, shopify-api
Is there any update on this issue? I'm wondering how to get the current customer behind the Shopify application proxy. I tried passing the customer-id into the URL (e.g. http://xxx.myshopify.com/app/proxied?cid=123456) but that is not secure enough since everyone can change the id on the URL.

ks.

Travis Haynes

unread,
Sep 5, 2012, 2:12:21 AM9/5/12
to shopify-a...@googlegroups.com
Using a private and public key-pair you could make this very secure. You can store the private key securely using Liquid code so it's never revealed to the customer. Then all you have to do is sign each request made to the proxy with the private key. It wouldn't matter if you put that in the URL field, since the key used to create the signature is hidden.

To create the signature, combine the data you'd like to sign with the private key, and pass that through the md5 filter, like this:

{% assign sig = settings.private_key + customer.id | md5 %}

This creates a unique signature that cannot be deciphered, or duplicated using a different customer ID without the private-key, which is hidden in the Liquid code. Then you could either use a form, or use some JavaScript to communicate with the application proxy. For example, here's what the form would look like:

<form action="/app/proxied" method="post">
  <input type="hidden" name="sig" value="{{ sig }}"/>
  <input type="hidden" name="customer_id" value="{{ customer.id }}"/>
</form>

And, finally on the server side, you need to validate the signature. Here's an example using Ruby:

require 'digest/md5'
signature = Digest::MD5.hexdigest(PRIVATE_KEY + params[:customer_id])
signature_valid = signature == params[:sig]

It's a bit confusing, but it's one of the most common ways to secure data between the client and server.

--
 
 
 

Travis Haynes

unread,
Sep 5, 2012, 2:16:06 AM9/5/12
to shopify-a...@googlegroups.com
Whoops, I meant one of the most common ways to validate data shared between the client and server, not to secure it. Securing the data would require using something like SSL.

mrkschan

unread,
Sep 5, 2012, 2:22:27 AM9/5/12
to shopify-a...@googlegroups.com
I get what you mean, so i'm going to put a signature onto the URL http://xxx.myshopify.com/app/proxied?cid=123456&sig=HWQIUBIAD where is signature is {{ customer.id + "this is a random string" | md5 }}. When my server process receive the request, i verify the signature with the salt "this is a random string" :)

Thanks. Why does this trick is not documented on the Wiki.

ks.

mrkschan

unread,
Sep 5, 2012, 2:31:34 AM9/5/12
to shopify-a...@googlegroups.com
Let me add one more thing to the trick, i think there should be a nonce being added into the signature or otherwise the request can be replayed.

In short, {% assign signature = customer.id + nonce + salt | md5 %}

ks

Travis Haynes

unread,
Sep 5, 2012, 2:34:44 AM9/5/12
to shopify-a...@googlegroups.com
As long as you're validating the proxy request is coming from Shopify, that shouldn't be an issue. But, if you do feel it's necessary, the best practice is to use a timestamp.

--
 
 
 

KSChan

unread,
Sep 5, 2012, 3:20:01 AM9/5/12
to shopify-a...@googlegroups.com
If the signature is {{ customer.id + time + salt | md5 }}, an action can still be replayed even if I check the signature from Shopify.

Consider the scenario, in a page that render a form to post a comment:


<form action="/app/proxied" method="post">
  <input type="hidden" name="sig" value="{{ customer.id + time + salt | md5 }}">
  <input type="hidden" name="customer" value="{{ customer.id }}">
  <input type="text" name="comment" value="">
  <button>Post</button>
</form>

A malicious user (via MITM for example) can mimic the HTTP post to mystore.myshopify.com and keep posting on behave of the customer since Shopify application proxy does not expose any info about the current visitor (whether her session is authenticated). Do you see the consequence?

ks

--
 
 
 



--
Please do not send me Microsoft Office/Apple iWork documents. Send OpenDocument (.pdf, .odt, .ods, .odp, etc.) instead! - http://fsf.org/campaigns/opendocument/

aboutme - http://about.me/mrkschan

Travis Haynes

unread,
Sep 5, 2012, 9:59:12 AM9/5/12
to shopify-a...@googlegroups.com
The purpose of using a timestamp is so you can ensure the request isn't too old. In your example, you would also want to include the timestamp as a parameter, so it could be checked on the server side:

<input type="hidden" name="ts" value="{{ timestamp }}" />

Also, if you're using a timestamp, and you need to be really paranoid about the requests, you could keep a record of the signatures that were processed in your database, and make sure that the same signature isn't used more than once. Although if you're project requires you to be that paranoid about the requests, you really should be using SSL.

--
 
 
 

KSChan

unread,
Sep 5, 2012, 9:22:27 PM9/5/12
to shopify-a...@googlegroups.com
I understand your point. What happen if the app proxy URL is supposed to be a landing URL that requires knowing the info of a customer.

For example, a link to the app proxy URL is added to the main menu of a store. That link is outside the Liquid returned from the app proxy. In this way, we cannot insert our salt to the link since it's not rendered from app proxy's Liquid.

I believe there are many other use cases that may need to know who is the customer behind the app proxy. If Shopify can add a X-Customer-Id HTTP header to the forwarded app proxy request or we can configure a set of token being forwarded, that can solve a lot of other use cases.

ks
Reply all
Reply to author
Forward
0 new messages