Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Security issue. Exposing all model to client #47

Closed
re1ro opened this issue Apr 26, 2012 · 16 comments
Closed

Security issue. Exposing all model to client #47

re1ro opened this issue Apr 26, 2012 · 16 comments

Comments

@re1ro
Copy link
Member

re1ro commented Apr 26, 2012

Problem

1

Let's look at chat example

2

If I set breakpoint on line 45 in browser (I mean equal line in compiled js)

42        ## CONTROLLER FUNCTIONS ##
43
44        ready (model) ->
45          months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
46          displayTime = (time) ->

3

I can do window.model = model in console

And continue script execution

4

In console

for (i in model.get('users'))
  model.set('users.'+i+'.name', 'lolz')

5

Name of every user is lolz

P.S.

Even in production environment, when js is uglified. I can do code reformat in chrome and put a breakpoint on function that has closure for model variable. And make that function happen. Like

c.postMessage = function() {
  return a.push("_room.messages", {userId: a.get("_session.userId"),comment: a.get("_newComment"),time: +(new Date)}), a.set("_newComment", "")
}

Where a is the model

I catch that breakpoint when I post a new message

@xcoderzach
Copy link
Contributor

This is something being actively developed. There will be a way to authorize model paths very soon, which should allow you to prevent this type of thing.

@re1ro
Copy link
Member Author

re1ro commented Apr 30, 2012

Guys!
I am really in love with derby because of transparent server-client rendering logic. But I am experiencing problems with architecting my application and having many security issues. And they all related to racer model representation. I understand that derby was created as upper layer for racer. But derbi is a really powerful framework for rendering, not for handling backend logic yet. As example you can't populate chat messages with user names on data managing level. If u have 1,000,000 users, u don't wanna do
model.fetch('users',....) and transfer it all on client, just to populate 10 chat messages with usernames through a template.

You don't have server-client logic separation. To be exact, you have some client only logic, but don't have server-only.
No web framework can be designed without server-private logic. And chat written on derby is a clear example that you can't write any application with user-private data with derby as it exists today. Because I can hack and change any user name, picture or message.

Please, let's consider other problems that I describe here.

1

I can't have any private things in app code. For example FB app token and secret. It all gets exposed to client which I don't want.
The temporary solution
I am putting lots of logic into racer middleware.

Solution
Every app piece should be able to have 2 files

app.js

// Rendering Routes
app.get ( pattern, callback(page, model, params, next) )

..........

// Server side listeners
ready (model) ->
  model.on 'set', 'user.email', (path, value, e) ->
    showEmailWarning() unless isValidEmail(value)

app.server.js

app.get ( pattern, callback(model, params, next){

  model.on 'set', 'user.email', (path, value, e) ->
    e.preventDefault() unless isValidEmail(value)
} )

2

Model needs to be able to store server only variables
Like model.set '_date', Today() is client only

Solution
We should have model.set '_session.$_datingWebsiteAccessToken', token as server only property.
And that code should be running on server only

3

I can run on client side
model.set('sessions',{all: 'loggedOut' }) or model.subscribe('whatever', messUpAllDatabaseInRealTime)```

My temporary solution
I won't use subscribe at all. Even if somebody starts to hack around - normal users won't see it in real time.
And for every route I use model.fetch to pull fresh data from my api (read more below).

Solution
There is should be "grand access" functionality. That runs on server only.

4

If I have in route
model.on('set',....)
And model.set happens on client - the listener is never firing on server.

Solution
Event emitter should fire both on client and server.

Conclusion

I use derby without any realtime cross-user racer functionality. And I use custom racer-db-driver that talks to our python written api.

Every user gets unhackable data like "#{hashedUserID}.updates.recent" witch is "updates/recent" endpoint of our api. And make reference "_updates" right away.

In this case I can even use subscribe to safely manage realtime data for one user if he has opened several tabs with the website.

@xcoderzach
Copy link
Contributor

More possibilities

#1
Here's a crazy Idea for server only code, but what if we parsed out blocks
of code that were inside of
functions like this:

server(function() {
secretServerOnlyStuff(secret1, secret2)
})()

and it got replaced with:

server()

by some browserify/asset processor

#2 & #3

agreed.

#4

I think this would be hard to do without memory leaking.

On Mon, Apr 30, 2012 at 5:10 PM, rma4ok <
reply@reply.github.com

wrote:

Guys!
I am really in love with derby because of transparent server-client
rendering logic. But I am experiencing problems with architecting my
application and having many security issues. And they all related to racer
model representation. I understand that derby was created as upper layer
for racer. But derbi is a really powerful framework for rendering, not for
handling backend logic yet. As example you can't populate chat messages
with user names on data managing level. If u have 1,000,000 users, u don't
wanna do
model.fetch('users',....) and transfer it all on client, just to
populate 10 chat messages with usernames through a template.

You don't have server-client logic separation. To be exact, you have some
client only logic, but don't have server-only.
No web framework can be designed without server-private logic. And chat
written on derby is a clear example that you can't write any application
with user-private data with derby as it exists today. Because I can hack
and change any user name, picture or message.

Please, let's consider other problems that I describe here.

1

I can't have any private things in app code. For example FB app token and
secret. It all gets exposed to client which I don't want.
The temporary solution
I am putting lots of logic into racer middleware.

Solution
Every app piece should be able to have 2 files

app.js

// Rendering Routes
app.get ( pattern, callback(page, model, params, next) )

..........

// Server side listeners
ready (model) ->
 model.on 'set', 'user.email', (path, value, e) ->
   showEmailWarning() unless isValidEmail(value)

app.server.js

app.get ( pattern, callback(model, params, next){

 model.on 'set', 'user.email', (path, value, e) ->
   e.preventDefault() unless isValidEmail(value)
} )

2

Model needs to be able to store server only variables
Like model.set '_date', Today() is client only

Solution
We should have model.set '_session.$_datingWebsiteAccessToken', token as server only property.
And that code should be running on server only

3

I can run on client side
model.set('sessions',{all: 'loggedOut' }) or model.subscribe('whatever', messUpAllDatabaseInRealTime)```

My temporary solution
I won't use subscribe at all. Even if somebody starts to hack around

  • normal users won't see it in real time.
    And for every route I use model.fetch to pull fresh data from my api
    (read more below).

Solution
There is should be "grand access" functionality. That runs on server only.

4

If I have in route
model.on('set',....)
And model.set happens on client - the listener is never firing on
server.

Solution
Event emitter should fire both on client and server.

Conclusion

I use derby without any realtime racer functionality. And I use custom
racer-db-driver that talks to our python written api.


Reply to this email directly or view it on GitHub:
#47 (comment)

@re1ro
Copy link
Member Author

re1ro commented Apr 30, 2012

Yeah, you are right about #4.

Please let me know what do you think about my updated conclusion

@re1ro
Copy link
Member Author

re1ro commented Apr 30, 2012

#1 Also it needs ability to do module = require 'module' that won't go through browserify to client.

@xcoderzach
Copy link
Contributor

I think you can do

module = require "" + 'module'

and it won't get browserified

On Mon, Apr 30, 2012 at 6:13 PM, rma4ok <
reply@reply.github.com

wrote:

#1 Also it needs ability to do module = require 'module' that won't
go through browserify to client.


Reply to this email directly or view it on GitHub:
#47 (comment)

@juzerali
Copy link

juzerali commented May 7, 2012

How about nowjs style authorization? Where we have groups and each model path belongs to a group.

@studgeek
Copy link

A little for insight on what they are thinking for AuthZ:

On 5/31/2012 3:08 PM, Nate Smith wrote:

Jae is correct that we don't have a solution for auth yet. We have an approach in mind, but the implementation is still forthcoming.
Unlike Meteor, you will not have to specify explicit publish functions in Derby. You will use the same dynamic subscriptions and methods from the app code. On top of that, you will be able to write server only code that acts as a gatekeeper before any requested gets, queries, or sets are allowed to access the database or the PubSub layer. Because incoming updates are coming via a WebSockets connection and not an HTTP request, we will take care of associating incoming updates with a session that can be used to perform authorization.
The necessary context and the specifics of the incoming get or set will be passed to a handler that can decide to allow or reject the incoming access or mutation.
Guarding gets and sets to a specific model path (like setting user.5.name to 'John') is relatively straightforward, but setting up auth for queries (like get the top 5 users sorted by high score) is more difficult. Queries are likely to have parameters that are a little different for every request but that have a pattern which should be matched against.
Once you turn on auth, the default will mostly likely be to simply block everything and then you will write handlers that allow gets or sets based on path patterns (like users.*.name) and queries with some ability to specify which parameters are dynamic.

  • Nate

@nateps
Copy link
Contributor

nateps commented Jul 16, 2012

First version of access control is now in. Needs more documentation and examples, but here is readme: https://github.com/codeparty/racer/blob/master/src/accessControl/README.md

@ariofrio
Copy link

That's a dead link, here is the new link: https://github.com/codeparty/racer/blob/master/lib/accessControl/README.md

@daslicht
Copy link

the new link is dead again :)

@digilord
Copy link

Any new movement here? I am moving away from Meteor and need a solid auth solution.

@SLaks
Copy link
Contributor

SLaks commented Aug 11, 2013

@digilord
Copy link

Are there any examples as to how to use this? The Meteor accounts-password package exposes a users collection. In some of the examples for Derby I see reference to users only as stored sessions. No passwords. They are only used to differentiate one browser session from another. racer-access seems to be akin to the Roles package from Meteor.

So perhaps my question should have been is there a user authentication package and some sort of authorization package available?

I apologize for the Meteor references, but it's the experiences I have to draw from for node based frameworks.

@SLaks
Copy link
Contributor

SLaks commented Aug 11, 2013

You're asking about authentication.

Derby does not include an authentication system.

Use https://github.com/lefnire/derby-auth (0.5 branch)

@daslicht
Copy link

the examples do not work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants