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

CLP (Read only) and write request using master key: #1976

Closed
neophob opened this issue Jun 2, 2016 · 26 comments · May be fixed by LadyK-21/parse-server#8
Closed

CLP (Read only) and write request using master key: #1976

neophob opened this issue Jun 2, 2016 · 26 comments · May be fixed by LadyK-21/parse-server#8

Comments

@neophob
Copy link
Contributor

neophob commented Jun 2, 2016

Issue Description

  • set READ Only CLP (Simple Config)
  • try to update an entry / create a new entry

According to the Parse Docs, using the master key for an action should bypass all security checks:

The master key, on the other hand, is definitely a security mechanism. Using the master key allows you to bypass all of your app's security mechanisms, such as class-level permissions and ACLs. Having the master key is like having root access to your app's servers, and you should guard your master key with the same zeal with which you would guard your production machines' root password.

Steps to reproduce

  1. Create a Custom Table, set CLP to read only
  2. Use this code to create a new entry:
exports.createNewEntry = function(param) {
  const ParseEntry = Parse.Object.extend('Yourname');
  let parseEntry = new ParseEntry();
  parseEntry.set('param', param);

  let acl = new Parse.ACL();
  acl.setPublicReadAccess(true);
  acl.setPublicWriteAccess(false);
  parseEntry.setACL(acl);

  return parseEntry.save({}, { useMasterKey: true })
    .then(parseEntry => {
       ...
    });
};
  1. Result: ERROR: ParseError { code: 119, message: 'Permission denied for this action.' }

When I edit the CLP and allow write permission (or only the Create in the advanced section) this code works.

Expected Results

Bypass CLP/ACL Permission when using Master Key

Actual Outcome

No Permission

Environment Setup

  • Server
    • parse-server version: 2.2.11
    • Operating System: Linux (Ubuntu)
@steven-supersolid
Copy link
Contributor

Where are you calling createNewEntry - in Cloud Code or client side JS? Cloud Code is trusted so the master key will be set when the SDK is initialized. You can also pass this to the JS SDK if initializing yourself but must only do so if the code is in a trusted environment.

Might be worth testing the same code with the ACL modification removed so you can see if there is a problem with just CLP and standard saving using the master key.

You could also try passing null as the first parameter to save instead of {}. I think either should work but have only tested null.

@neophob
Copy link
Contributor Author

neophob commented Jun 4, 2016

I call this function from client side js. i initialized the sdk with the mater key. I also tried the null param instead the {} variant with the same result.

when i change the clp permission and add write permission it works.

@flovilmart
Copy link
Contributor

I'll have a look tomorrow. Do you confirm the behavior is different than on parse.com?

@flovilmart
Copy link
Contributor

Something is sure, that should pass with the masterKey

@flovilmart
Copy link
Contributor

flovilmart commented Jun 5, 2016

I call this function from client side js. i initialized the sdk with the mater key.

This is plain wrong... You should not let your masterKey in the client SDK!

@flovilmart
Copy link
Contributor

I just ran some tests, and this behaves correctly, the masterKey is correctly processed when running from the server.

Again, the masterKey SHOULD NEVER EVER EVER been sent to the client.

Also, if you look at the code here: https://github.com/ParsePlatform/Parse-SDK-JS/blob/master/src/Parse.js#L32

The masterKey is completely ignored when Parse is used in the Client SDK.

@neophob
Copy link
Contributor Author

neophob commented Jun 5, 2016

hi. i dont deploy rhe master key with my app. i only use it for admin tasks. but I think When Im using cloud code and do security checks there it should work aswell.

thanks

@flovilmart
Copy link
Contributor

Can you provide the logs when running parse-server with VERBOSE=1

@flovilmart flovilmart reopened this Jun 5, 2016
@neophob
Copy link
Contributor Author

neophob commented Jun 6, 2016

sure, clientcode:

const ParseMyClass = Parse.Object.extend('MyClass');
let myClassEntry = new ParseMyClass();
myClassEntry.set('param1', 'CC');
myClassEntry.set('param2', 'BB');
myClassEntry.set('param3', 'AA');

let acl = new Parse.ACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(false);
myClassEntry.setACL(acl);

return myClassEntry.save({}, { useMasterKey: true })
  .then(entry => {
    console.log('done');
  });

server code (hint: log direction is upside down):


verbose�: error: code=119, message=Permission denied for this action. 
} 
"param1": "CC" 
"param2": "BB", 
"param3": "AA", 
}, 
} 
"read": true 
"*": { 
"ACL": { 
'x-forwarded-port': '80' } { 
'content-type': 'text/plain', 
accept: '*/*', 
'user-agent': 'node-XMLHttpRequest, Parse/js1.8.5 (NodeJS 4.3.2)', 
'x-forwarded-proto': 'http', 
'content-length': '249', 
'x-forwarded-for': '-removed-, -removed-', 
'accept-encoding': 'gzip', 
connection: 'Close', 
�verbose�: POST /parse/classes/MyClass { host: '-removed-',

@flovilmart
Copy link
Contributor

When you say client code, from where is that code run from?

@neophob
Copy link
Contributor Author

neophob commented Jun 6, 2016

from my workstation (aka. NOT cloud code and NOT on the same device as the server runns)

@flovilmart
Copy link
Contributor

How do you require parse? With require("parse/node") ?

@neophob
Copy link
Contributor Author

neophob commented Jun 6, 2016

correct yes:

const Parse = require('parse/node');
const PARSE_MASTER_KEY = process.env.XXX_MASTERKEY;
const PARSE_SERVER = process.env.XXX_SERVER;
const PARSE_APPID = process.env.XXX_APPID;
Parse.initialize(PARSE_APPID, '', PARSE_MASTER_KEY);
Parse.serverURL = PARSE_SERVER;

(the master key is obsolete but doesn't hurt)

@sdf611097
Copy link
Contributor

How you do this step?

  1. Create a Custom Table, set CLP to read only

@davimacedo
Copy link
Member

davimacedo commented Jun 8, 2016

To make it works, you will have to save your function as a cloud function in your parse server cloud code and then call it from client (your workstation).

In our main.js, create samething like:

Parse.Cloud.define("createNewEntry", function (request, response) {
  const ParseEntry = Parse.Object.extend('Yourname');
  let parseEntry = new ParseEntry();
  parseEntry.set('param', request.params.param);

  let acl = new Parse.ACL();
  acl.setPublicReadAccess(true);
  acl.setPublicWriteAccess(false);
  parseEntry.setACL(acl);

 parseEntry.save({}, { useMasterKey: true })
    .then(parseEntry => {
       ...
       response.success(parseEntry);
    }).catch(response.error);
});

In your client call just function like:

Parse.Cloud.run("createNewEntry", {param: "param"}).then(parseEntry => {
  ...
});

@neophob
Copy link
Contributor Author

neophob commented Jun 8, 2016

@davimacedo thanks for your reply. I don't think having admin related tasks in cloud code make sense - security wise and user wise.

@flovilmart any hints from your side?

@davimacedo
Copy link
Member

@neophob you can first check in your cloud function if user is 'admin'

Actually it is the unique way to make it works since sending master key from client (admin is also client) is not recommended/allowed anymore as you can see in the link @flovilmart sent:
https://github.com/ParsePlatform/Parse-SDK-JS/blob/master/src/Parse.js#L32

@neophob
Copy link
Contributor Author

neophob commented Jun 8, 2016

Hmm I'm a bit confused now. In a recent parse SDK commit (parse-community/Parse-SDK-JS@8a3d011) the documentation was updated, the changed text:

useMasterKey: In Cloud Code and Node only, causes the Master Key to be used for this request.

So it looks like the docs clearly say we can use the masterKey from node, but how do we actually SET the master key?

@davimacedo
Copy link
Member

Hi @neophob I've just realized that you are using in a Node.js environment and there userMarterKey: true should be working. Sorry about that.

When you pasted your initialization code, you said: "(the master key is obsolete but doesn't hurt)"
What do you mean?

@neophob
Copy link
Contributor Author

neophob commented Jun 9, 2016

From parse.js sdk (node)

  /**
   * Call this method first to set up your authentication tokens for Parse.
   * You can get your keys from the Data Browser on parse.com.
   * @method initialize
   * @param {String} applicationId Your Parse Application ID.
   * @param {String} javaScriptKey (optional) Your Parse JavaScript Key (Not needed for parse-server)
   * @param {String} masterKey (optional) Your Parse Master Key. (Node.js only!)
   * @static
   */
  initialize: function initialize(applicationId, javaScriptKey) {
    Parse._initialize(applicationId, javaScriptKey);
  },

  _initialize: function _initialize(applicationId, javaScriptKey, masterKey) {
    _CoreManager2['default'].set('APPLICATION_ID', applicationId);
    _CoreManager2['default'].set('JAVASCRIPT_KEY', javaScriptKey);
    _CoreManager2['default'].set('MASTER_KEY', masterKey);
    _CoreManager2['default'].set('USE_MASTER_KEY', false);
  }

...

Parse.initialize = Parse._initialize;

I just saw that the Parse.initialize = Parse._initialize; is available on node.js only. So correction: this should work when initializing with the master key...

@neophob
Copy link
Contributor Author

neophob commented Jun 22, 2016

any news on this issue?

@neophob
Copy link
Contributor Author

neophob commented Jun 22, 2016

seems to work with latest parse server now (v2.2.13)

@neophob neophob closed this as completed Jun 22, 2016
@11k
Copy link

11k commented Jul 19, 2016

Just want to pop in and say that this works for me only if I call Parse.Cloud.useMasterKey() in addition to passing { useMasterKey: true } as an option to each operation that needs to bypass CLPs/ACLs.

@haroot
Copy link

haroot commented Aug 15, 2018

here is how you override CLPs/ACLs for protected Collections starting with a "_" persay like "_User" aka "User"

async function updateByUserId(id, field, value) {
  const query = new Parse.Query(Parse.User);
  const user = await query.get(id, { useMasterKey: true });
  user.set(field, value);
  return user.save(null, { useMasterKey: true });
}

@flovilmart
Copy link
Contributor

@haroot I edited the snippet to remove inaccuracies with the latest and future versions of the server

@haroot
Copy link

haroot commented Aug 15, 2018

@flovilmart thanks ill replace the old one in the morning . A lot cleaner, thank you!

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

Successfully merging a pull request may close this issue.

7 participants