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?

Peter Mortensen
  • 1,050
  • 2
  • 12
  • 14
GWed
  • 3,085
  • 5
  • 26
  • 43
  • Is this related to a iOS app? – Grim Jul 30 '14 at 13:15
  • 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) – thorsten müller Jul 30 '14 at 13:17
  • I'm tying to further my learning on how developers are creating browser only apps. – GWed Jul 30 '14 at 13:19
  • Every tool can be a weapon in malicious hands. – Shadur Jul 30 '14 at 15:04
  • 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. – Kevin Panko Jul 30 '14 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 '14 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 '14 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. http://blogs.technet.com/b/rhalbheer/archive/2011/06/16/ten-immutable-laws-of-security-version-2-0.aspx – Dan Is Fiddling By Firelight Jul 31 '14 at 15:44

8 Answers8

203

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.

Peter Mortensen
  • 1,050
  • 2
  • 12
  • 14
Kilian Foth
  • 107,706
  • 45
  • 295
  • 310
  • 2
    +1 nice answer. Before writing this question, I thought the same as you. Thanks for validating. All the developers I speak with who are raving about client side apps are, as I thought, quite reckless in the pursuit of that cutting edge. – GWed Jul 30 '14 at 13:42
  • 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 '14 at 15:18
  • Kompletely korrekt. In fakt, koders like myself depend on this mere fakt in that it makes surfing the web easier. I don't like the way most pages I "like" are laid out. There's stupid ads, and iframes, and sometimes just crappy layotus. So aside from stylebot, i have my own "extension" that allows me to save JS for specific sites or even specific pages i visit I can basically, make everything the way i want to see it. This includes changes to the way i look facebook, removes all adds from youtube, cuts out all the extra crap on ebay, etc... Point is, you can't control the user end. – SpYk3HH Jul 30 '14 at 17:03
  • 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. – Kilian Foth Jul 30 '14 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 '14 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](http://programmers.stackexchange.com/a/251746/94235)) – Ajedi32 Jul 30 '14 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!!**. –  Jul 30 '14 at 23:29
  • 2
    @Ajedi32 Clients are *always* inherently insecure, and if they probably aren't at the moment, you still have man-in-the-middle and all sorts of potential attacks, alternate clients, etc. You *must never* trust the client. If security matters on a particular operation, you do it on the server and deliver safe results to the client. What the client does after that is not necessarily your problem (if the client machine is compromised and logs traffic, you can't help that). You can still mitigate most data leaks by not sending the client anything it shouldn't have. – ssube Jul 31 '14 at 18:35
  • 5
    @ssube Depends on what you mean by "secure". If you're trying to secure client side software against attacks by the client itself, then yes, you're fighting a losing battle. If, however, you're talking about the security of the client side software against attacks by external forces then yes, it's totally possible to build a "secure" client-side application. "never trust the client" is about protecting the security of your server, not the security of client-side app. – Ajedi32 Jul 31 '14 at 19:47
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.

jhocking
  • 2,641
  • 19
  • 18
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.

Jan Hudec
  • 18,250
  • 1
  • 39
  • 62
  • 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 '14 at 09: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?

Brandon
  • 4,555
  • 19
  • 21
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.

LMSingh
  • 277
  • 2
  • 5
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.

Matt Klinker
  • 179
  • 4
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).

gnasher729
  • 42,090
  • 4
  • 59
  • 119
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."

Depado
  • 101
  • 1