9

I have to design a "widget", a script that partners will embed in their websites to display some UI and make calls to our API.

Basically it will display our data on these sites based on some IDs they provide in our API calls. What we would like to avoid is someone abusing the API and using it to scrape the entirety of our catalog.

Each partner that embeds our script will be given a public key that must be provided when calling the API. An idea would be to ask them to append this key when loading the script, e.g.:

<script src="//initrode.com/widget/loader.js?key=xxxx"></script>

That way the request for the script can be used to register the key/source IP pair, and answer subsequent API calls only if the key/IP pair matches a registered one (with a limited lifetime, and a limit on requests per day).

I'm not sure it's a good idea since it's obviously security through obfuscation (someone reloading the script will completely bypass it) ; but I don't see any other way to restrict access. I cannot provide a unique key to every user, only to partners. I can't use a private-key system since all the code will be available to anyone. It's basically restricting access to a public API, i.e. contradictory in its definition.

What do you think of this solution, and what would you do with these constraints?

  • Can you make the key dynamic? MD5 hash of the partner's identifier plus the UTC time rounded to the nearest 10 minutes? – Dan Pichelman Feb 21 '14 at 15:57
  • 2
    I can, but that will be computed in the script, and as such available freely for anyone to reproduce it. I don't see how that improves security. – Antoine Feb 21 '14 at 16:00
  • I was thinking of having the partner compute it server side. If that's not an option, then I suspect your only real choice is to do the throttling you mention (limited lifetime, limit on requests/day). Don't forget that the IP you see doesn't necessarily map to a single computer. – Dan Pichelman Feb 21 '14 at 16:03
  • I need to check with the business if to compute it server-side is feasible. Otherwise that's what I feared, only solution is throttling. – Antoine Feb 21 '14 at 16:17
12

You need several types of protection.

Firstly, you need to prevent Site A's key from being used on Site B.

In theory, if the key is bound to a domain, you can't depend on the referer header, but because you're client is embedding a script directly, you can reasonably rely on the document.location on the client-side. Sending that location (or portions of it) to the server directly is unreliable; but you can use it to generate a session key:

  1. Client embeds client_key in request for API library.
  2. Server determines host that has access to the API, if any.
  3. Server picks "salt" for a session key and sends it to the client with the library [or as part of another pre-auth exchange].
  4. Client calculates a session_key using hash(document.location.host + session_salt).
  5. Client uses session_key + client_key for an API call.
  6. Server validates the call by looking up the client_key's host and "salt" in the session, computing the hash, and comparing to the provided client_key.

Secondly, you need to impede Hacker Hank from opening the debug console or using a modified client on Site A to do whatever he wants with your API.

Note though, that it's very difficult, if not impossible, to completely prevent Hacker Hank from abusing the API. But, you can make it more difficult. And the most reasonably way to impede Hank, that I'm aware of, is rate limiting.

  • Limit the number of requests/second/session and requests/hour/session. (Spikes in activity are probably reasonable, but not sustained above-average traffic from a single client.)
  • Limit the number of sessions/IP/hour.
  • Limit the number of requests/IP/hour. Allow spikes, but not sustained heavy traffic from a single IP.

Thirdly, as you're likely already doing: encrypt the traffic. Sure, the NSA will see it; but Hacker Hank is less likely to.

0

Sounds like you're doing here making your javascript files into protected resources. And bundling it with a sort of token generation at the same time. That's interesting.

The security guys I work with usually dismiss IP address out of hand because IP is spoofable. But if you're using an IP restriction combined with SSL, that usually does the trick.

But you have to "whitelist" the IP addresses, otherwise any hacker can just come in the front door.

I was skeptical, but I'm actually thinking your scheme works pretty well. If 1) the .js file and subsequent API calls are made with TLS (i.e. SSL or https), and 2) the IPs are whitelisted. Then I'll make a bold statement and say I think you'd pass a security review, even for PCI (credit card) interactions.

IMHO... But if you're just trying to protect company-proprietary information instead of credit card (PCI) or personal / private information (PII), then this is probably good even even without SSL, depending on how much you're willing to risk exposing your catalogue.

Or put it this way: With SSL, a dedicated hacker could not get your catalog. (Unless they break SSL, but then they could break Amazon, too). Without SSL, a dedicated hacker could sniff your calls, spoof IP and pull down your catalog. So it's kind of a judgement call on the risk.

I'm trying to think of a way to dispense with the IP whitelist because that's usually a pain to manage ;) without going to full-blown OAuth. I'll noodle on that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.