Preventing JSON domain spoofing
<p>Here's the scenario. A customer already has an eCommerce site where they are collecting shipping address info and credit card data. However, they sign up with a SaaS service that allows them to easily change their credit card form <strong>to also collect fullnames and emails</strong> (not credit card info) into a marketing system for other purposes. So, they paste a jQuery snippet into their page from the SaaS service and add some "data-" attributes to their form and form field tags so that the SaaS service knows what to intercept and where to what SaaS account to post the data.</p>

<p>Okay, but then a security problem occurs. Let's say we have two separate customers in that SaaS system. One is named Jack and owns jack.com, and his account ID is 100001. The other is Nancy, nancy.com, and 100002. Jack could add the snippet into his form and add some "data-" attributes, but then screw up and set his account ID in one of those data- attributes to 100002 instead of 100001. This would mean that Nancy would suddenly see Jack's data in her account. Not good! The fix, of course, is to have some setting in Jack's SaaS account so that he only accepts data from jack.com, and Nancy only accepts data from nancy.com.</p>

<p>But then a potential exploit happens. All a hacker has to do is create a spoof page on his own server where he forms similar JSON and, via a /etc/hosts file change on his workstation, makes it appear that he's jack.com. He could then fire in thousands upon thousands of bogus marketing form information into Jack's account because the SaaS service thinks it's coming from jack.com.</p>

<p>Is there anything I can do in the jQuery code, or the PHP code used by the SaaS service, to ensure that a hacker can't spoof like that and that only Jack's real customer data gets sent?</p>

<p><strong>ANSWERED QUESTIONS</strong></p>

<p>Q1. "How do you identify Jack and Nancy? By domain?"</p>

<p>A1. Jack has his domain jack.com. Nancy has her domain nancy.com. Each use this marketing SaaS service, but each are also co-opting an eCommerce form they already had before they signed up for the SaaS service. They were told in the SaaS docs, "Just drop the scraper.js in your form page and add these data- tags to your form tag and html input, textarea, and select tags so that the scraper.js can intercept those form submits temporarily, glean the marketing data (full name and email, let's say) from that form, and then let that form submit on its workflow that you already had. The data- attributes would identify which account is to be used, as well as which marketing campaign and sub-campaign where this data should be stored at the SaaS service." However, in the jQuery of scraper.js, it was going to pass in the JSON the location.href property so that it knows what domain was used -- jack.com or nancy.com, in this particular instance. Trouble is -- the location.href can be spoofed by a hacker who sets up an /etc/hosts file entry of 127.0.0.1 for jack.com on his workstation and runs a copy of the same JSON code.</p>

<p>Q2. "What if you could use a callback mechanism from SaaS.com to jack.com? So, one of your data- attributes would specify the callback function to receive data back from SaaS.com, and then only save data when it gets the right response?"</p>

<p>A2. Now that's an interesting take. Yeah, so I could like drop an extra PHP page on jack.com that emits "OK". When SaaS.com receives a JSON data post from jack.com, it sends a request to that second PHP callback page on jack.com with file_get_contents() to ensure it not only gets the OK response back, but also gets a match on IP address and SSL certificate data. If the two are different, then most likely the request was a bogus hacker request and the transaction can be security logged and rejected. (I can do the IP address verification easily, but am not certain how to verify the same two SSL certificates in PHP, if that's even allowed or possible.) Of course, IP addresses can be spoofed.</p>

<p>Another layer of security on this is that this second PHP page can use a public/private key exchange communication check between SaaS.com and jack.com instead of simply emitting "OK".</p>

<p>Q3. "Why would you want to intercept payment information and send that off through Javascript?"</p>

<p>A3. Absolutely not. Never specified sending payment information in this question. Was saying something like Full Name and Email, instead. Yes, SSL communication would need to be used as well in order to send that data securely. And, we'd have to use <a href="https://stripe.com/blog/stripejs-and-jsonp" rel="nofollow">JSONP to get around the CORS problem</a>.</p>

<p>Q4. "Wouldn't that require jack.com to have everything saved in a database for verification? If so, why bother with the SaaS app?"</p>

<p>A4. Nope. Not at all. Check out the answer A2. With that mechanism, the SaaS app receives the data, but doesn't trust it until 2 things happen:</p>

<ol>
<li><p>It calls back to jack.com to a second page, and ensures that the response it gets back has the same IP address as the one that sent the form data in the first place.</p></li>
<li><p>It does a public/private key exchange check (which the hacker can't spoof obviously unless they have server access) in that second page to ensure that IP spoofing wasn't occurring.</p></li>
</ol>

<p>Q5. Wait a minute. A2 and A4 have a problem. The IP address of the initial sending request will be from the user's workstation, not the server. So, you can't validate IP that way. You'll have to use another mechanism to validate that someone completed the form at jack.com and that it wasn't from a hacker spoofing jack.com.</p>

<p>A5. You're absolutely right. Forgot about that I guess because I'm slightly distracted on another project. I'll have to give this some more thought.</p>