61

Over the last few years, the trend for client-side (browser) applications has really taken off.

For my latest project, I have decided to try and move with the times and write a client-side application.

Part of this application involves sending transaction emails to users (for example, validate signup, password reset emails, etc.). I am using a third-party API to send the emails.

Normally I would have my application running on a server. I would call the third-party API from code on my server.

Running a client-side application means this now needs to happen on a user's browser. The third-party API provides the necessary JavaScript files to achieve this.

The first glaring issue I can see is I need to use an API key. This would normally be safely stored on my server, but now presumably I will need to provide this key to the client browser.

Assuming I can get round this problem, the next problem is what stops a tech-savvy user loading up the JavaScript developers tool on a browser and using the email API anyway they like, rather than say adhering to any rules I have set in the application.

I guess my general question is - how can we prevent malicious use of a client-side application?

8
  • 25
    Any reason you don't have this App communicate with your own server and then your server forwards those requests to whatever external service you need to use? (Many such services would prohibit to use them in this way anyway) Jul 30, 2014 at 13:17
  • 11
    This is why API keys are ultimately pointless. The server should not be trying to trust the app that is sending it commands; it should only trust the user. Jul 30, 2014 at 16:37
  • 43
    I haven't seen any sane person ever define "client-side application" as "under no circumstance ever communicate with a server" - that seems more like a strawman than a reasonable argument. Clearly there are some things you have to handle on the server-side but the vast majority of actions can be done locally without problems, which will in turn vastly improve responsiveness and scalability..
    – Voo
    Jul 30, 2014 at 20:50
  • 4
    Where do you see a push towards "Browser Only Apps?" I've never seen anything like what you're describing, keeping secrets in client code in an insanely bad idea, even the most die-hard front end guys I know would never do that.
    – Wheeyls
    Jul 30, 2014 at 22:48
  • 2
    Any attempt to protect secure resources client-side is doomed because it violates several of the immutable laws of security. #2/3 - if your software is running on your adversaries computer it's not your computer by definition and you've already lost. #7 attempting to protect a resource by encryption is doomed since you also have to provide the client the decryption key. #10 no technology can fix the above. blogs.technet.com/b/rhalbheer/archive/2011/06/16/… Jul 31, 2014 at 15:44

8 Answers 8

202

You can't, and the more people understand this, and the deeper they understand, the better for the world.

Code that runs on a device under the user's control cannot be controlled. Smartphones can be jailbroken. Set-top boxes can be cracked. Ordinary browsers don't even attempt to prevent access to JavaScript code. If you have something worth stealing or abusing, a determined attacker will be able to do that unless you validate everything you cherish server-side.

Obfuscation is of very little help; the kind of opponent you will attract as soon as anything remotely financial is involved reads assembly language like classified ads. Encryption cannot help you, because the device that would guard the key is the same device you have to assume is cracked. There are many other, seemingly-obvious countermeasures that don't work, for similar reasons.

Unfortunately, this is a very inconvenient truth. The world is full of small-time and big-time operators who think they can somehow get around the fundamental brokenness of remote trust, simply because it would be oh so nice if we could assume that our code will be run the way we assumed. And yes, it would make everything so much easier that it isn't even funny. But wishing doesn't make it so, and hoping against hope that you are the one smart cookie who can avoid the unpleasantness will only burn you and your clients. Therefore, get into the mindset that the Internet is enemy territory, include that added cost in your estimates, and you'll be fine.

That said, of course there is such a thing as defense in depth. Obfuscating your JavaScript doesn't put off a determined attacker, but it may put off some less-determined attackers. If your assets are worth enough to protect, but not at any cost, any of those measures may add business value to your system; it just can't be perfect. As long as you are fully aware of the trade-off you are making, that may be a reasonable strategy.

9
  • 6
    But to put this in perspective: This is true for EVERY Software, be it an Operating System or a transaction suit. In the end there are some very good code obfuscators out there and you can raise the bar most likely high enough, if there is no immediate financial incentive to hacking your software!
    – Falco
    Jul 30, 2014 at 15:18
  • 5
    These days, companies have taken to threatening legal action against people who hack the content received from them before processing (i.e. via ad blockers). That only goes to show how impossible technical action is. Jul 30, 2014 at 17:32
  • 64
    If I may elaborate on the first two sentences, the subtlety folks often miss is that point of client-side browser apps is to offload heavy lifting. Your server is still responsible for trusted operations, like sending emails or accessing the data. Having the client render a graph from that data, however, saves you CPU time (and money) without changing the security model.
    – ssube
    Jul 30, 2014 at 18:52
  • 11
    @Gaz_Edge It's important to note that the problem here is not that client-side apps are inherently insecure. The problem is writing these client side apps in a way that requires trusting the client with information you don't want to be public. It's totally possible to write a client-heavy application that is just as secure as an application where most of the processing happens on the server. (For more on that, see jhocking's answer)
    – Ajedi32
    Jul 30, 2014 at 20:29
  • 7
    @Ajedi32 Client-side apps are insecure. It is impossible to design a secure app if any logic done client-side isn't checked server-side. At that point the client-side logic becomes a UI nicety or a way to offload basic checks, but everything, must always be checked on server!!.
    – user69037
    Jul 30, 2014 at 23:29
70

The rule here is:

Do everything client-side that doesn't affect anyone else if the user tampers with it. In particular, that means graphical effects.

Do everything server-side that needs to be secure, and just send UI events from the client (eg. then client just says "the user tapped the Buy button" while the server actually carries out the transaction). In particular, that means financial transactions.

28

This is exactly the case where making it a completely client-side application is not appropriate.

You can make the logic and basic validation of forms client-side (you still have to revalidate on server, because someone may try to fake the request) to improve responsiveness, you can do HTTP requests from JavaScript passing data there and back in JSON to avoid re-sending page decorations and such, but if the transaction itself needs to be authenticated and authorized, it should still happen on a server.

1
  • 11
    Note: While it great to validate forms client side, never ever forget to also validate them server side! By the time you send your client code to the browser, it stops being your code! You have to validate every single bit it sends again!
    – Josef
    Jul 31, 2014 at 9:22
17

Your middle paragraph is the heart of the problem:

Running a client side app means this now needs to happen on a users browser. The third party API provides the necessary js files to achieve this.

Why does a client side app mean you cannot have server-side work? The push towards client-side programming isn't about eliminating servers, but leveraging newer technologies that browsers finally support to make better user interfaces.

As for the .js file you received, are you sure it is meant for a browser? Could it be a node.js library?

1
  • 4
    +1 for the really good suggestion that the JS file is intended for a NodeJS server Aug 1, 2014 at 9:34
11

Let's step back from this and take a higher level look.. shall we.. Did Eudora or outlook (a client side app, not even needing a browser) ever cause a financial loss for any company? No. Anyone could write to the POP/SMTP API's and be the client. But no loss to the server. The server didn't limit client actions, computations, storage, temperature, disk size, ram size, monitor DPI, GPU, FPU yada yada of the client but exactly specified what it would answer to and no more. Did you ever hear of quicken or MS-Money being used to break to a bank?

Your browser (i.e. client side) app can use the same architecture.

  1. You build your server with an API (which BTW, always boils down to derivatives of GET POST HEAD etc.).
  2. On the server, ensure that the API only talks with an authenticated and identity verified client for each and every call.
  3. Then you don't care who the client is.
  4. And then you don't care if it's a browser, jailbroken device, Google glass, DOS 3.1, or a brand new Nexus in the hands of a technophobe great-great-great-great-grandpa who has time traveled to 2014 and missed all the technology that's been flooding our lives in the last 15 decades.
  5. Now you can start off-loading everything else to client side.

SoapBoxBegin

@KilianFoth raises an important awareness point for the naive and the reckless, mainly those who read the headlines all the time but never think it will happen to their app, their code, their employer, their client, their own bank account. Even more reckless are their employers (especially the CTO's) who would allow apps to get out that expose any systems to unmanaged/uncontrolled exposure. However I'm always puzzled at how it seems "we never learn".

SoapBoxEnd

So to summarize. Make a solid and tight server side API. Offload everything else to client based on whatever the client can handle.

6

I'd argue that you really can't. If you're willing to send the data to the client, you must expect that it will be abused - however possible. Your example regarding the API key is illustrative of the point, and I would not include that in your client side JS - it will be stolen and abused.

You definitely will still need some amount of server code to keep things secure. Even something as simple as retrieving just the data related to the logged in user. That authentication can't all be done client side or again you will be taken advantage of and your data is not secure.

I would always view the JS client side experience to be an addition to server code. Validation on client provides a nice user experience, but if you don't verify that POST data on the receiving server as well, you're opening yourself up to attack. Anything from the client should be considered suspect.

0
4

It's quite simple, really. Assume that the client computer and all software running on it is under complete control of a clever malicious hacker.

That means that any information that you send from the server to the client will be known to the malicious hacker, so you must make sure to send out no information to the client that could be used to attack your server or your business.

It also means that anything sent from the client to the server has been produced by the malicious hacker, so your server code must make sure that nothing the client could send would be capable of successfully attacking your server.

Admittedly, the implementation is a problem, but the important thing is the mental attitude, the assumption that the "client" you think your server is talking to isn't a client but an active attacker.

(You also need to assume that the user is a clever conman who will try to attack your business methods, but that has nothing to do with client-side programming).

0

Client-Side application, in my opinion, is mostly about the UI. For example, all your UI system will be sent once to the client, and then the client would do whatever it wants with it.

Normally I would have my application running on a server. I would call the third-party API from code on my server.

Running a client-side application means this now needs to happen on a user's browser. The third-party API provides the necessary JavaScript files to achieve this.

If you have an API Key, then it's not intended to work on the client side. If you give the API Key on the client side, then anyone has access to it, and can then use it for it's own purpose. Store it and use it server-side when the client needs it, then send the result using Ajax/WebSockets.

It's like if your bank was saying : "Well, I'm going to put the password of the main database client side so that the client can request it himself and he will not bother our servers anymore."

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