Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Possible Duplicate:
Writing Web “server less” applications

So, let's say I'm going to build a Stack Exchange clone and I decide to use something like CouchDB as my backend store. If I use their built-in authentication and database-level authorization, is there any reason not to allow the client-side Javascript to write directly to the publicly available CouchDB server? Since this is basically a CRUD application and the business logic consists of "Only the author can edit their post" I don't see much of a need to have a layer between the client-side stuff and the database. I would simply use validation on the CouchDB side to make sure someone isn't putting in garbage data and make sure that permissions are set properly so that users can only read their own _user data. The rendering would be done client-side by something like AngularJS. In essence you could just have a CouchDB server and a bunch of "static" pages and you're good to go. You wouldn't need any kind of server-side processing, just something that could serve up the HTML pages.

Opening my database up to the world seems wrong, but in this scenario I can't think of why as long as permissions are set properly. It goes against my instinct as a web developer, but I can't think of a good reason. So, why is this a bad idea?

EDIT: Looks like there is a similar discussion here: Writing Web "server less" applications

EDIT: Awesome discussion so far, and I appreciate everyone's feedback! I feel like I should add a few generic assumptions instead of calling out CouchDB and AngularJS specifically. So let's assume that:

  • The database can authenticate users directly from its hidden store
  • All database communication would happen over SSL
  • Data validation can (but maybe shouldn't?) be handled by the database
  • The only authorization we care about other than admin functions is someone only being allowed to edit their own post
  • We're perfectly fine with everyone being able to read all data (EXCEPT user records which may contain password hashes)
  • Administrative functions would be restricted by database authorization
  • No one can add themselves to an administrator role
  • The database is relatively easy to scale
  • There is little to no true business logic; this is a basic CRUD app
share|improve this question
    
Not exactly pure "client side to database", but have you looked at Parse and Firebase? (and also Meteor to some level), all of them have somewhat relevant concepts, and all handle security in creative ways. e.g. see this: blog.firebase.com/post/38234264120/… – Eran Medan Dec 19 '12 at 18:59
    
Yes! I'd heard of Parse before but not Firebase. Very interesting, and definitely along the lines of what I was thinking. – Chris Smith Dec 19 '12 at 20:53
    
How would your database protect against SQL injection or XSS being sent from the JavaScript? Pretty much anything sent from the client you have to assume it's unsafe, so what provisions are there in that database you can use to filter the data to make sure it's valid and insert data with prepared statements? – zuallauz Dec 20 '12 at 3:45
5  
Ignoring everything else, you're creating a 2 tier application, which tightly couples your UI to the database. Not really a good idea unless your app is trivial. – Andy Feb 19 at 23:43
9  
SSL won't stop someone running DELETE FROM ImportantData; – immibis Feb 20 at 2:54

14 Answers 14

up vote 38 down vote accepted

Doing as you suggest creates a tight(er) coupling between your client side language and your database.

That can be okay - there's less code to write and maintain, and in theory debugging could / should go a little quicker.

On the other hand, it makes other aspects more difficult. If / when you need to change either of those technologies, you'll have a harder time because of the tight coupling between them.

Protecting yourself against attacks will be (quite) a bit more difficult. You're assuming that the client will always present nicely formatted requests to the database. That presumes no one will ever hack the client side code to insert malicious statements. In other words, they'll "borrow" your authentication mechanisms and replace the normal client code with theirs.

I wouldn't recommend it, and many would vehemently tell you not to. But it can be done.

share|improve this answer
    
Interesting. How might an attacker borrow my authentication mechanism? I wouldn't be trusting the client to authenticate. The database would simply take an HTTPS POST to the session endpoint that would hash the POSTed password and check that it's valid. If it is, then it would return a session cookie to be used in future requests. – Chris Smith Dec 19 '12 at 15:15
1  
All I need is the session cookie, right? I use your client to auth and get my session cookie. Then I steal the session cookie with my client and send up badly formatted requests to cause havoc. Remember that it's all on my machine, so I don't even need a MiTM attack. – GlenH7 Dec 19 '12 at 15:33
5  
@ChrisSmith - so long as you feel you're addressing the security concerns then you're handling the primary objection to what you suggested. If you've got them handled or think you do then go for it. The simple version of your question is this: You asked why people don't do ABC. The primary answer is security and tight-coupling. Address those concerns and code away. – GlenH7 Dec 19 '12 at 16:14
2  
Not to mention you don't have a place to cache frequently-requested data, so you'll have to hit the DB every time. Sure, maybe your DB driver does some caching, but how tunable is it? Will it share across threads? – TMN Dec 19 '12 at 17:18
1  
I'm uncomfortable allowing direct access to my sql databases via direct sql statements from web clients because you never know what type of requests they'll be making. Will they run delete, update, or insert statements? If they do, will they provide the data your application expects? Will unexpected deletions happen? Unexpected database changes will usually break your application. It's best to minimize the commands going to your database so you can more easily sanitize the inputs you receive so your application has a better chance of working right. – Nathan Pilling Dec 19 '12 at 18:19

It's probably not a great idea. And the first and strongest reason I can give is that a database server isn't designed to be a public web server. To the contrary, conventional wisdom says you should hide your database behind a firewall.

If you need supporting evidence, there are plenty of concerns -- not all insurmountable, but plenty to think about. In no particular order, here are a few:

  • It can't perform query sanitization, because you're sending it the queries directly.
  • Database permissions tend to work differently than web server and application permissions. Web servers and application frameworks start you with nothing, and you need to explicitly create and expose individual resources, endpoints, and actions. Databases, on the other hand, ask you to grant roles at a high level.
  • It's probably not well-optimized to sustain a web server's workload; you can't benefit from connection pooling.
  • The more popular web servers have been broken into a lot. And they've received a lot of security patches. Your DBMS has basically been designed to hide behind a firewall, so it probably hasn't been tested by even a fraction of a percent of the potential threats it will face on the public web.
  • You must use the database's query language to protect private data. Depending on your DBMS, that can be challenging.
  • You must use the database's query language to filter large data sets -- something you might strive to do anyway; but something that can become burdensome for more complicated business rules.
  • Limited or no support for third party libraries.
  • Very limited (potentially zero) community support for many of the problems you'll encounter.

... And I'm sure there are other concerns. And I'm sure there's a solution to most -- if not all of these concerns. But, there's a list to get you started!

share|improve this answer

The best single reason I can imagine is: because this method is not directly supported or recommended by any involved party.

Browser vendors, EcmaScript standards, database system developers, networking equipment companies, hosting/infrastructure architects, and security specialists do not actively support (or perhaps even consider) your proposed use case. This is a problem, because your proposed method requires all of these entities - and more - to work appropriately for your application, even though none of the involved systems were designed to support this.

I'm not saying it's not possible. I'm just saying this is less like "re-inventing the wheel" and more like re-inventing browser-based client-server interaction.

At best, you'll be doing a ton of work to even get the systems to work at the most basic possible level. Modern popular databases are not RESTful or built to work over HTTP, so you'll be building your own WebSocket-based (I presume) client drivers.

Even if you get everything to technically work, you will be giving up many of the most powerful features of modern architectures. You will have no defense in depth - everyone can easily connect directly to the primary target of most website hacking attempts. But the scenario you propose is much, much worse than that.

The proposed model is not just exposing the server - it's exposing valid connection strings. Attackers can't just ping the server - they can actively login and feed it commands. Even if you can limit data access, I'm not aware of sufficient tooling in DBMS systems to protect from Denial of Service scenarios and their ilk. When working in enhanced versions of SQL, like TSQL, it's often trivially easy to produce bombs that run effectively infinitely (a few unrestricted joins to produce a Cartesian product and you'll have a SELECT that'll run for ever, doing heavy work). I'd imagine you'd need to disable most of the features of SQL, even eliminating basic SELECT queries with JOINs and perhaps only allow calling stored procedures? I don't even know if you can do that, I've never been asked to try. It doesn't sound good.

Database scalability also tends to be one of the hardest problems in working at large scales, while scaling out multiple HTTP servers - especially with static or cached pages - is one of the easiest parts. Your proposal makes the database do more work by being responsible for basically 100% of server-side activity. That's a killer flaw all by itself. What you gain from moving work onto the client you lose by moving more work onto the database.

Finally, I'd just like to point out that the heart of what you propose is not new, but actually goes back decades. This model is called the "fat database" model, which basically moved most server-side logic into the database just as you propose. There's many reasons that model has gone by the wayside on the mass internet, and it would probably be informative to look more into that history yourself. Note also that even then there was little consideration of having completely untrusted users able to login to the system and run commands, as access would still be controlled to select internal (known) users who weren't supposed to be attacking the system constantly.

The fact is that you'll still need an HTTP server to serve files, as database systems just don't do that. At the same time, everything you propose can be obtained by using a thin server model (such as with Nodejs) to expose a RESTful interface to your database. This is popular for a reason - it works, keeps the database hidden away behind layers of protection, is extremely scalable, and yet allows you to build your database as thick or as thin as you care to.

share|improve this answer

Since this is basically a CRUD application and the business logic consists of "Only the author can edit their post" I don't see much of a need to have a layer between the client-side stuff and the database. I would simply use validation on the CouchDB side to make sure someone isn't putting in garbage data and make sure that permissions are set properly so that users can only read their own _user data.

Well, placing your authorization (the security concerns) and logic validation away from Database provides separation of concerns in your software system. Thus you may test, maintain, scale and reuse your logical code blocks with less risks of braking the functionality in the system.

Providing ability for client input directly communicate with Database has very big potential to screw up the data.

This also means that avoiding/removing tight coupling make your software system more maintainable and SOLID.

share|improve this answer
1  
I would normally agree with this, but I can test, maintain and scale code blocks within the client-side code just as easily as server-side. Doing it all in Javascript wouldn't be an excuse not to use proper separation of concerns. I'm simply moving the actual processing from the server to the client. So what is having the layer in between buying me? – Chris Smith Dec 19 '12 at 15:18
2  
Having client-side validation is nice for client, but having it in place on your server side is more critical than ever. Because, your client side request can be easily simulated. Having logical separations and/or tiers helps in sociability and maintainability. – Yusubov Dec 19 '12 at 15:24
    
So, playing devil's advocate: As I mentioned below, I could use CouchDB's validation functions to determine whether data being submitted is valid. Whenever you try to add or update a document, it would check that you're allowed and that it's correctly formatted. It puts more processing on the database side, but it is fairly lightweight and I need to consider scaling the data side anyway. Wouldn't this address the concern? – Chris Smith Dec 19 '12 at 15:33
    
No, i don't think so. Placing your validation and authorization logic in DB is going to be performance hit on your system, once record numbers start to grow and you get more users on your system. – Yusubov Dec 19 '12 at 16:15
    
The DB engines are meant to store and retrieve the data, not to manipulate or validate it. Of course you can do it your way, but it is not the efficient way to follow. – Yusubov Dec 19 '12 at 16:16

Letting the user interact with the database directly seems really dangerous to me.

Is the authentication mechanism of CouchDB really so sophisticated that you can isolate the read- and write access of a user only to the data it is supposed to read and write (we are talking about per-document, maybe even per-document-field access privileges here)? What about "communal" data which is shared by multiple users? Doesn't this exist at all in your application design?

Do you really want the user to be able to change its data in ANY way? What about XSS injections, for example? Wouldn't it be better to have a server layer to filter those before they get into the database?

share|improve this answer
1  
You bring up good points, and I thought the same thing. I came to the conclusion that in this (hypothetical) application, I'm okay with anyone reading anything EXCEPT user records. They can only write to documents that they have originally created (which is the only "business logic" I mentioned above). CouchDB seems to have the ability to do both of these things through their internal _users database and validation functions. – Chris Smith Dec 19 '12 at 16:44

If your security checks and business logic are contained in your client side javascript, they can be overridden by a malicious user. As an alternative, you can leverage a JavaScript based server-side technology (like Node.JS) to handle validation, authorization, and the like.

share|improve this answer
    
Authentication and authorization would be handled by the database itself, so I wouldn't be trusting the client at all in that regard. CouchDB has built-in validation functions that fire whenever you try to update a document so I would use those to check that what is being submitted is valid. – Chris Smith Dec 19 '12 at 15:30

You've gotten a number of reasons, but here's one more: future-proofing. Sooner or later, as your application evolves, you'll be presented with some requirement that can't be readily or securely achieved in client-side JS or as a stored procedure in your database.

For instance, you're told that all new registrations need to have a CAPTCHA verification to be valid. This would be really easy enough with pretty much any modern web application framework. Just slap a reCAPTCHA on the registration form, pass reCAPTCHA's response token back to the backend, and add a couple lines of code to your backend to verify the token's validity with Google's API (or better yet, use a library someone else wrote to do that for you).

If you're using a two-tier system and relying on the database for all your server-side logic, how are you going to verify the token? Yes, I suppose it might be theoretically possible depending on the DBMS to write a stored procedure that somehow calls a shell and invokes curl with the proper arguments. That is also almost certainly a horrible idea: input filtering and protecting against security vulnerabilities would be terrible; you'd have a mess dealing with error handling and timeouts; and you'd have to parse the response yourself. Not to mention that a DBMS isn't intended to do this, so there's no reason to think performance, stability, thread-safety, etc... won't be issues. See, for instance, this thread, which discusses some of these issues for Postgres.

And that's just the issues around adding one simple CAPTCHA to a form. What are you going to do if you want to add SMS verification, or a background job that emails inactive users to remind them about your app, or add a file upload feature so people can set a profile picture? Maybe you decide your application should have some automated tests someday? Or that you'd like to track changes to your procedures in a version control system? There are numerous libraries and tools for most any useful language to handle most of these tasks for you, but few to none will be available for your DBMS, because it's not meant to do this.

Eventually, you'll want to do something that you can't reasonably do directly in your DBMS, and then you'll be stuck. Because you'll have built your entire application in your DBMS, you won't have any alternative but to get a web server and start rebuilding pieces in another language, just to add a simple feature.

And that would be a real shame, because we already have a name for the place where you put your application logic, and it's called "your application's source code" rather than "database stored procedures" for a reason.

share|improve this answer

Any business constraint you may want to ensure should be validated server side. Even if you control user access, someone may send invalid data.

Following your stackoverflow clone example:

  • How would you block "closed" questions on the site from being edited anyway?
  • How would you prevent people deleting comments?
  • How would you prevent people from faking comment dates?
  • How would you prevent people from upvoting 50 times the same post?
  • There are probably a lot more examples if you dig a little bit more.

Any one could manipulate the client side code and violate data integrity completely (even if restricted to certain objects, like their own posts).

share|improve this answer

Edit page in firebug and at some point put a line similar to this:

ExecDbCommand("DROP TABLE Users")

Run it.

Edit:

The question was in fact about CounchDB so no sql to run here. Yet the idea is the same. I would presume that any non trivial application depends on data to respect some consistency rules that are checked/enforced by the application code. A malicious user can modify the client code to save data in a form that violates your business rules and might cause havoc in your application.

If your site considers all possible data states to be valid from a business perspective then by all means go this route but if this is not the case (likely) then you would want to have the guarantee that any data that gets stored is generated by your code and according to your rules.

share|improve this answer
    
CouchDB wouldn't know what to do with that, but I get your point. If permissions are set properly, the response to such a thing would be a 401 Unauthorized. – Chris Smith Dec 19 '12 at 16:46
    
-1, when you post SQL code you obviously don't even know what CouchDB is. Also, just by creating an admin account on CouchDB you already prevent any other user from performing the most dangerous operations. – Philipp Dec 19 '12 at 16:47
    
fair enough. i skipped the part on CouchDB in the question and only registered it as "access data store from client side JS directly". I'll edit response. – AZ01 Dec 19 '12 at 16:51
1  
+1, SQL or not, his point still holds. A JS debugger could be used to alter how data is accessed. – GrandmasterB Dec 19 '12 at 16:55

I think that, given all of your assumptions, it's feasible to go directly from the client to the database. However, it's reasonable to look at whether your assumptions are valid, and are likely to remain so in the future.

I would be worried that in the future it might not be OK for everyone to read all the data, and especially that it might develop more business logic in the future. Both of these are more likely if the project is successful.

As long as you leave yourself a way to deal with these problems in the future when and if you actually need to deal with them I think your design will work. I think you will need to be extra careful to separate concerns in the JavaScript code, and some of it might end up be rewritten on the server later.

But I could definitely see where it might be worth a risk of maybe doing that later vs. the benefit of fewer moving parts today.

share|improve this answer
    
Good point. This is definitely a narrow use-case, so it's not something you could apply to any application. – Chris Smith Dec 19 '12 at 19:04

First of all thanks for the OUT OF THE BOX question.... :)

But what i would suggest is; Always try to maintain a segregation between your 3 layers. which are Presentation/Business and Database or DAO because that will be the best practice in those kinds of requirements and setups where there will be lots of changes every day.

In simple worlds your Presentation layer should not know about Database layer i.e. Format of some date type fields might be different from presentation layer and database layer so that user can have a freedom to select suitable format of the date as per his/her needs.

And Business Logic must act like a coupling between presentation layer and database/Dao layer like casting of the fields, some business validations, etc should be handled on Business Layer rather than in Javascript section as per your question.

This segregation will provide you great ease and comport during complex scenarios, functionality-es and even complex validations. The best advantage is: you can have different technologies to implement these layers and can be changed as per the business needs or scope.

Thanks

share|improve this answer

If you would like to build SQL in JavaScript and send it to the database, which verify the rights etc., than from security reason it would be a disaster. Simply because when you build an API, and build queries yourself, you have to analyse from the point of view of the security only the limited number of queries. If the queries are built outside your system, you have potentially unlimited number of tricks that someone could do.

But it's not the case since you are using key-value database (as fair as I understand, CouchDB generally falls into that category). The database interface itself is a kind of middle layer, and it is tested for security reasons by Apache team. Because of relatively simple JavaScript API this is even easier to analyse for potential flaws than such complicated interfaces that JSF applications have.

This can be a secure solution, if you do complex security tests. This can be even easier as when using frameworks such as JSF, which are often using hardly readable API behind. Security by obscurity is considered no solution.

Relating to your question, it won't be direct access to database anyway. Direct access would be the building SQL queries in JavaScript (unfortunatelly, I've seen such solutions). In your case the CouchDB itself provides the isolation layer. You could of course wrap it in your API to harden it, but as long as you can easily test what can particular user do and if the security constraints are working for you, you will have secure and robust solution without additional layers.

share|improve this answer

I see two problems:

1. Tight Coupling: Change your DB option? Well, now you gotta change all your client-side code too. Trust me. We don't need more problems on the client-side.

2. TMI Security Issue: Reveals way too much about how stuff works. Auth might still be an obstacle but finding an exploit is a Hell of a lot easier when you know exactly what's happening on the server-side.

A very-very-thin middle-tier might be a better way to go.

share|improve this answer

Your client cannot use your web app if javascript is disabled (or not supported on the browser of his device) if javascript is the only database-access-layer.

share|improve this answer
1  
Eh, not too worried about this. Most of the web now relies on Javascript anyway. I might just have to break out the <noscript> tags and tell them they need to turn it on if they want my site (and 80% of the other ones out there) to work. – Chris Smith Dec 19 '12 at 15:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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